<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Codesai</title>
    <description>Posts</description>
    <link>https://www.codesai.com</link>
    
      
        <item>
          <title>Our Architectural Guardrails for AI-Generated Code</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;The idea to write this post came about almost half a year ago, but the flood of events in the industry and my personal life has not allowed me to write about it until now.&lt;/p&gt;

&lt;p&gt;During a deliberate practice session&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; where the pair I was assisting was programming using &lt;a href=&quot;https://cursor.com/&quot;&gt;Cursor&lt;/a&gt;, I watched in amazement as &lt;a href=&quot;https://cursor.com/&quot;&gt;Cursor&lt;/a&gt;’s autocomplete suggested using test builders to instantiate an object in production code, and nobody noticed.&lt;/p&gt;

&lt;p&gt;I pointed out the problem to the pair so they could fix it, and advised them to be more careful with what the AI ​​was suggesting. But I was left with the feeling that my advice is much easier said than done, because it’s not easy to always be vigilant, since it’s difficult to spot problems in code that’s mostly fine. This difficulty is exacerbated when the code is generated by agents due to the sheer volume of code generated.&lt;/p&gt;

&lt;p&gt;I believe we need all the help we can get in this task of evaluating AI-generated code.&lt;/p&gt;

&lt;h2 id=&quot;what-wed-like-to-avoid&quot;&gt;What we’d like to avoid.&lt;/h2&gt;

&lt;p&gt;As we’ve already discussed, the speed and size of the increments when using code agents make it harder for developers to detect these problems. When evaluating code that appears mostly correct for extended periods, phenomena like &lt;a href=&quot;https://tylercipriani.com/blog/2022/03/12/code-review-procrastination-and-clarity/&quot;&gt;code review fatigue&lt;/a&gt; or &lt;a href=&quot;https://youarenotsosmart.com/2026/04/13/yanss-337-how-to-maintain-your-critical-thinking-and-avoid-cognitive-surrender-when-using-ai-to-solve-problems-make-decisions-and-learn-new-things/&quot;&gt;cognitive surrender&lt;/a&gt; can occur, making one more likely to accept AI-generated code (even small amounts suggested by autocomplete) without careful evaluation.&lt;/p&gt;

&lt;p&gt;This evaluation of AI-generated code gets even more difficult when developers have not yet developed enough knowledge to have criteria to evaluate the design implicit in the solution proposed by AI.&lt;/p&gt;

&lt;p&gt;Since one of the main objectives of deliberate practice sessions is precisely to develop critical skills to evaluate design options&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;, we decided to support the participants with some minimal design rules that automated away basic problems we’d like to avoid&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;1-domain-should-not-depend-on-infrastructure&quot;&gt;1. &lt;strong&gt;Domain should not depend on infrastructure&lt;/strong&gt;.&lt;/h3&gt;

&lt;p&gt;Business rules should guide software system design because they represent the core logic and purpose of the organization, which should remain independent from changing technologies or external systems. In addition, by isolating the domain from infrastructure, the business logic remains easier to test, maintain, and evolve independently of external technologies. This approach also reduces accidental complexity, avoiding the leakage of infrastructure details into the business language and preserving a cleaner, more adaptable architecture.&lt;/p&gt;

&lt;p&gt;This rule helps us strictly keep the dependency rule described in the &lt;a href=&quot;https://www.happycoders.eu/software-craftsmanship/hexagonal-architecture/&quot;&gt;ports and adapters pattern&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-production-code-should-not-have-circular-dependencies&quot;&gt;2. &lt;strong&gt;Production code should not have circular dependencies&lt;/strong&gt;.&lt;/h3&gt;

&lt;p&gt;Circular dependencies because they blur module boundaries and make systems harder to understand, maintain, and safely evolve. Changes in one component tend to propagate unpredictably into the other, increasing coupling and making refactoring riskier. Cycles also create fragile initialization behavior, often causing import-order issues or partially initialized objects at runtime. Most importantly, they hurt testability: components cannot be instantiated or mocked independently, which makes unit testing and dependency injection harder and pushes teams toward slower, more brittle integration tests.&lt;/p&gt;

&lt;h3 id=&quot;3-production-code-should-not-depend-on-tests&quot;&gt;3. &lt;strong&gt;Production code should not depend on tests&lt;/strong&gt;.&lt;/h3&gt;

&lt;p&gt;Production code should not depend on tests because tests are meant to verify behavior, not define or support runtime structure. When production relies on tests, it creates tight coupling between validation code and application logic, making the system fragile and harder to maintain. Changes to tests can unintentionally affect production behavior, undermining the reliability and independence that tests are supposed to provide. This creates fragility and deployment risks. It also blurs responsibilities by making tests both validators and runtime collaborators, which undermines separation of concerns. Such coupling encourages the introduction of test hooks, fake abstractions, and conditional behaviors into production code, reducing cohesion and maintainability.&lt;/p&gt;

&lt;p&gt;This may seem obvious, but it was precisely this rule that I observed code suggested by &lt;a href=&quot;https://cursor.com/&quot;&gt;Cursor&lt;/a&gt; breaking.&lt;/p&gt;

&lt;h2 id=&quot;how-to-enforce-these-design-rules&quot;&gt;How to enforce these design rules.&lt;/h2&gt;

&lt;p&gt;We evaluated three primary enforcement strategies: &lt;strong&gt;architecture tests&lt;/strong&gt;, &lt;strong&gt;reviews with agents&lt;/strong&gt;, and &lt;strong&gt;documentation/skills&lt;/strong&gt;, but in the end, we decided to use &lt;strong&gt;architecture tests&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;why-not-skills-docs-or-agentic-reviews-guidelines-vs-guardrails-determinism-and-costs&quot;&gt;Why not skills, docs or agentic reviews: guidelines vs guardrails, determinism and costs.&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Architecture tests&lt;/strong&gt; are automated tests that can be used to verify the structure and design of our code to a certain extent, and as such, can help us enforce some design rules, acting as automated constraints that make it deterministically “difficult to do the wrong thing.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; (like &lt;a href=&quot;https://agents.md/&quot;&gt;AGENTS.md&lt;/a&gt;) and &lt;a href=&quot;https://agentskills.io/home&quot;&gt;skills for agents&lt;/a&gt; are used to enhance the probability of generating code according to what we expect. While they are essential when working with coding agents, they function merely as &lt;a href=&quot;https://ideas.riverglide.com/what-people-get-wrong-about-agent-guardrails-80a2f7f98d73&quot;&gt;guidelines&lt;/a&gt;, and, as such, we think they are too weak to enforce design rules like the ones mentioned above. We think that, in the case of design rules like ours, we need to move from “best effort” to “guaranteed compliance,” shifting our focus from &lt;strong&gt;guidelines&lt;/strong&gt; toward &lt;a href=&quot;https://ideas.riverglide.com/what-people-get-wrong-about-agent-guardrails-80a2f7f98d73&quot;&gt;guardrails&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviews with agents&lt;/strong&gt;, while being a form of &lt;strong&gt;guardrail&lt;/strong&gt;, introduce a layer of probabilistic uncertainty and recurring costs that make them less reliable and more expensive, respectively, than architecture tests.&lt;/p&gt;

&lt;p&gt;The following analysis explains in more detail why we prioritize deterministic architecture tests over the other options evaluating them across two critical dimensions: &lt;strong&gt;likelihood of adherence&lt;/strong&gt; and &lt;strong&gt;token cost and efficiency&lt;/strong&gt;.&lt;/p&gt;

&lt;h4 id=&quot;1-architecture-tests-a-reliable-guardrail&quot;&gt;1. Architecture Tests (a reliable guardrail).&lt;/h4&gt;

&lt;p&gt;Architecture tests turn objective design rules into executable code&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h5 id=&quot;a-likelihood-of-adherence&quot;&gt;a. Likelihood of adherence.&lt;/h5&gt;

&lt;p&gt;Architecture tests are fully deterministic. If we integrate them into our CI/CD pipeline, we achieve a 100% adherence rate because a rule violation physically prevents the build from passing, they act as binary gates for the rules. They are automated fitness functions&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; that ensure the enforcement of the design rules.&lt;/p&gt;

&lt;h5 id=&quot;b-token-cost-and-efficiency&quot;&gt;b. Token Cost and Efficiency.&lt;/h5&gt;

&lt;p&gt;These tests execute locally on the CPU with zero token cost. They provide instant feedback during the inner development loop without hitting any external API, making them the most cost-effective and lowest-latency option.&lt;/p&gt;

&lt;h4 id=&quot;2-docsskills-guidelines&quot;&gt;2. Docs/Skills (guidelines).&lt;/h4&gt;

&lt;p&gt;Documentation and skills rely on human memory and/or the LLM’s ability to follow  instructions.&lt;/p&gt;

&lt;h5 id=&quot;a-likelihood-of-adherence-1&quot;&gt;a. Likelihood of adherence.&lt;/h5&gt;

&lt;p&gt;Documentation and skills enhance the probability of getting a generated code that follows our design rules.&lt;/p&gt;

&lt;p&gt;Under pressure or high cognitive load, humans tend to prioritize task completion over structural constraints. In a similar way an agent, due to the non-deterministic nature of LLMs, may ignore instructions, or take shortcuts in their eagerness to complete tasks.&lt;/p&gt;

&lt;p&gt;Agents can also suffer from their version of high cognitive load, suffering from instruction-following degradation as their &lt;a href=&quot;https://www.ibm.com/think/topics/context-window&quot;&gt;context window&lt;/a&gt; gets too full: &lt;a href=&quot;https://www.trychroma.com/research/context-rot&quot;&gt;context rot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The amount of documentation we feed an agent can worsen &lt;strong&gt;context rot&lt;/strong&gt; because every rule added to a loaded “skill” library or prepended to a prompt consumes space in the context window. We need to be careful deciding which skills and documentation are worthy to occupy space in the context window.&lt;/p&gt;

&lt;p&gt;Even if we manage effectively the context window, the important point is that design rules defined as &lt;strong&gt;guidelines&lt;/strong&gt; are susceptible to “drift.” because agents may often bypass or forget &lt;strong&gt;guidelines&lt;/strong&gt;.&lt;/p&gt;

&lt;h5 id=&quot;b-token-cost-and-efficiency-1&quot;&gt;b. Token Cost and Efficiency.&lt;/h5&gt;

&lt;p&gt;Every loaded “skill” or documentation prepended to a prompt lead to higher per-request costs and increased latency.&lt;/p&gt;

&lt;p&gt;We also saw how &lt;strong&gt;context rot&lt;/strong&gt; produces a performance degradation which may require more attempts to complete a given task increasing the number of requests.&lt;/p&gt;

&lt;p&gt;Unlike “free” local architecture tests, enforcing design rules that are really objective like ours using documentation or skills creates an increase in operating costs.&lt;/p&gt;

&lt;h4 id=&quot;3-reviews-with-agents-an-unreliable-guardrail&quot;&gt;3. Reviews with Agents (an unreliable guardrail).&lt;/h4&gt;

&lt;p&gt;This method uses a second LLM pass to “audit” code against a set of standards (passed as documentation or skills).&lt;/p&gt;

&lt;h5 id=&quot;a-likelihood-of-adherence-2&quot;&gt;a. Likelihood of adherence.&lt;/h5&gt;

&lt;p&gt;Because agentic reasoning is non-deterministic, this kind of enforcement will be “best-effort” rather than guaranteed. It is probabilistic and inconsistent by nature. An agent may overlook subtle violations if the primary logic looks correct. This creates an unreliable feedback loop where the same violation might pass one review and fail the next.&lt;/p&gt;

&lt;h5 id=&quot;b-token-cost-and-efficiency-2&quot;&gt;b. Token Cost and Efficiency.&lt;/h5&gt;

&lt;p&gt;This approach introduces a massive “token tax.” Every line of code must be sent and processed twice, once for generation and once for verification. This leads to escalating API costs and higher latency, making constant evaluation of design rules an expensive recurring expense, and a source of happiness for your AI-inference providers 😅.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion.&lt;/h4&gt;

&lt;p&gt;We hope that we have been able to communicate with this analysis the reasons why we prefer to use architecture tests to enforce design rules like ours rather than the two other options: they are an automatic, cost-effective, unambiguous, deterministic and reliable way to enforce objective rules.&lt;/p&gt;

&lt;h4 id=&quot;linters-vs-architecture-tests-for-design-rules&quot;&gt;Linters vs. architecture tests for design rules.&lt;/h4&gt;

&lt;p&gt;We also experimented with &lt;a href=&quot;https://en.wikipedia.org/wiki/Lint_(software)&quot;&gt;linters&lt;/a&gt; as &lt;strong&gt;guardrails&lt;/strong&gt; to enforce our design rules. From the point of view of &lt;strong&gt;likelihood of adherence&lt;/strong&gt;, as well as &lt;strong&gt;token cost and efficiency&lt;/strong&gt;, linters are as valid as architecture tests. Both approaches can automatically reject changes that violate predefined constraints, making them equally viable enforcement mechanisms.&lt;/p&gt;

&lt;p&gt;However, we prefer architecture tests over linters because we find that architecture tests make the intent of design rules easier to read. With architecture tests, design rules are usually expressed directly in code, and described by the name or description of the test itself. In linters, the same rules tend to live in JSON or configuration files, in a more cryptic format that is harder to interpret at a glance.&lt;/p&gt;

&lt;h2 id=&quot;our-minimal-architecture-tests&quot;&gt;Our minimal architecture tests.&lt;/h2&gt;

&lt;p&gt;We wrote these architecture tests with the help of a coding agent and then did “agentic mutation testing” in the code to see if they really detected violations of the rule, (we’ll talk more about agentic mutation testing, and how to &lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/talk/&quot;&gt;offload it to determinism&lt;/a&gt; in a future post).&lt;/p&gt;

&lt;h3 id=&quot;for-the-deliberate-practice-sessions&quot;&gt;For the deliberate practice sessions.&lt;/h3&gt;

&lt;p&gt;These are the architecture tests in TypeScript we are using in the deliberated practice sessions:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/84691f57f8c0a4bb2bee127d78d0cf31.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We used basic functionalities from the &lt;a href=&quot;https://lukasniessen.github.io/ArchUnitTS/&quot;&gt;ArchUnitTS&lt;/a&gt; architecture testing library to enforce our minimal design rules.&lt;/p&gt;

&lt;h3 id=&quot;for-a-clients-project&quot;&gt;For a client’s project.&lt;/h3&gt;

&lt;p&gt;We have also added architecture tests to a project my colleague &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and I are developing for a client.&lt;/p&gt;

&lt;p&gt;We hadn’t felt the need to automatically enforce design rules in this project until we started using agents to delegate some tasks. When Fran and I were pair programming without agents we never produced the problems those rules are meant to avoid, probably thanks to keeping a more human pace and sharing a mental model through pair programming. But now that we’re using coding agents, we decided that adding architecture tests to the project would be helpful.&lt;/p&gt;

&lt;p&gt;These are the architecture tests in Java we are using in our project:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/05e1a23927f95b3bbf645c8c1f2361f0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;They contain more rules than the ones we use for the deliberate practice sessions. In this case, we are using &lt;a href=&quot;https://www.archunit.org/&quot;&gt;ArchUnit&lt;/a&gt; architecture testing library (which I think is a complicated beast) to enforce the design rules.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h2&gt;

&lt;p&gt;The frequency and size of AI-generated code increments often outpaces our natural capacity for vigilance. The risk of cognitive surrender or fatigue is real. When an LLM consistently produces code that looks “mostly right,” it becomes increasingly difficult to spot subtle design drifts. We think that relying solely on &lt;strong&gt;guidelines&lt;/strong&gt; is insufficient to maintain high design standards under these conditions.&lt;/p&gt;

&lt;p&gt;We believe that to successfully integrate AI agents into our workflow, we must complement &lt;strong&gt;guidelines&lt;/strong&gt; with &lt;strong&gt;guardrails&lt;/strong&gt;. While documentation and skills can help steer an LLM in the right direction, they remain probabilistic and context-heavy. By contrast, architecture tests offer a deterministic, cost-effective way to ensure compliance. They allow us to at least offload the mental burden of structural verification to the CPU, enforcing our core design rules regardless of who, or what, is writing the code.&lt;/p&gt;

&lt;p&gt;By implementing minimal architecture tests, we have created a safety net that protects our core design rules. These tests function as automated fitness functions that provide instant, local feedback. This approach continually enforces our design rules without burning any token.&lt;/p&gt;

&lt;p&gt;We are using these tests, both in deliberate practice sessions and client projects, in which AI-generated code is growing. In our experience, they have proven very useful because while we cannot always prevent an agent from generating code that breaks a desired design rule, &lt;strong&gt;guardrails&lt;/strong&gt; like architecture tests can certainly prevent that code from ever becoming a permanent part of our system.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/fernandoaparicio/&quot;&gt;Fernando Aparicio&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ideas.riverglide.com/what-people-get-wrong-about-agent-guardrails-80a2f7f98d73&quot;&gt;What We All Got Wrong About Guardrails&lt;/a&gt;, &lt;a href=&quot;https://antonymarcano.com/&quot;&gt;Antony Marcano&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/harness-engineering.html&quot;&gt;Harness engineering for coding agent users&lt;/a&gt;, &lt;a href=&quot;https://birgitta.info/&quot;&gt;Birgitta Boeckeler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=uLWOLmeHOSE&quot;&gt;Harness engineering beyond skills: Using sensors to keep your coding agent in check&lt;/a&gt;, &lt;a href=&quot;https://birgitta.info/&quot;&gt;Birgitta Boeckeler&lt;/a&gt;, &lt;a href=&quot;https://www.thoughtworks.com/es-es/profiles/service-line-leads/chris-ford&quot;&gt;Chris Ford&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781492097532/&quot;&gt;Building Evolutionary Architectures, 2nd edition&lt;/a&gt;, &lt;a href=&quot;https://nealford.com/&quot;&gt;Neal Ford&lt;/a&gt;, &lt;a href=&quot;https://www.thoughtworks.com/en-es/profiles/leaders/rebecca-parsons&quot;&gt;Rebecca Parsons&lt;/a&gt;, &lt;a href=&quot;https://www.thoughtworks.com/en-es/profiles/p/patrick-kua&quot;&gt;Patrick Kua&lt;/a&gt;, &lt;a href=&quot;https://www.sadalage.com/&quot;&gt;Pramod Sadalage&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/talk/&quot;&gt;Offload Deterministic&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/lada-kesseler/&quot;&gt;Lada Kesseler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.milanjovanovic.tech/blog/enforcing-software-architecture-with-architecture-tests&quot;&gt;Enforcing Software Architecture With Architecture Tests&lt;/a&gt;, &lt;a href=&quot;https://www.milanjovanovic.tech/blog&quot;&gt;Milan Jovanović&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://lukasniessen.github.io/ArchUnitTS/&quot;&gt;ArchUnitTS - Architecture Testing&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.archunit.org/&quot;&gt;ArchUnit: Unit test your Java architecture&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Our deliberate practice sessions with &lt;a href=&quot;https://www.audiense.com/&quot;&gt;Audiense&lt;/a&gt; are designed with two goals in mind:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Keep fundamental engineering skills strong, avoiding &lt;a href=&quot;https://addyo.substack.com/p/avoiding-skill-atrophy-in-the-age&quot;&gt;skill atrophy induced by AI&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Introduce new technical practices and ideas to the team on a continuous basis.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2]  In the deliberate practice sessions, we try to transmit a style of OO design based on the &lt;a href=&quot;https://www.goodreads.com/en/book/show/213172609-hexagonal-architecture-explained&quot;&gt;ports and adapters pattern&lt;/a&gt; combined with &lt;a href=&quot;https://en.wikipedia.org/wiki/Responsibility-driven_design&quot;&gt;Responsibility-driven design&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;Domain-Driven Design&lt;/a&gt; principles, other OOP principles, and when they apply, some &lt;a href=&quot;https://en.wikipedia.org/wiki/Design_Patterns&quot;&gt;classical OOP design patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3]  We could also have banned AI completely during deliberate practice sessions. Instead we decided to work without agents, but still allow using AI autocomplete in the IDEs. The reason for this is that we believe that generating code at a more “human pace” is more instructive for learning and practicing the type of skills we want to develop and maintain.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] According to &lt;a href=&quot;https://birgitta.info/&quot;&gt;Birgitta Boeckeler&lt;/a&gt; “LLMs are great for exploratory and fuzzy rules, but once you have [a rule] that really is objective, converting it to a formal, unambiguous, deterministic format can give you more assurance”.&lt;/p&gt;

&lt;p&gt;Our design rules are objective, so they are best implemented in a formal, unambiguous, and deterministic format such as architecture tests or linter rules.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] To learn more about &lt;strong&gt;fitness functions&lt;/strong&gt; have a look at chapter 2 of &lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781492097532/&quot;&gt;Building Evolutionary Architectures, 2nd edition&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2026-04-26T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/04/minimal-architecture-constrainsts-in-agentic-world</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/04/minimal-architecture-constrainsts-in-agentic-world</guid>
        </item>
      
    
      
        <item>
          <title>Roots of the mock trauma in a Flash</title>
          <description>&lt;div class=&quot;flashcard&quot;&gt;
&lt;h3&gt;Roots of the mock trauma.&lt;/h3&gt;

&lt;hr class=&quot;flashcard-line&quot; /&gt;

&lt;ul&gt;
    &lt;li&gt;The &lt;b&gt;problem&lt;/b&gt; is &lt;b&gt;usually caused&lt;/b&gt; by either:
        &lt;ol type=&quot;a&quot;&gt;
            &lt;li&gt;&lt;b&gt;Design problems&lt;/b&gt; in &lt;b&gt;production code&lt;/b&gt;
                &lt;ul&gt;
                    &lt;li&gt; &lt;b&gt;Procedural code&lt;/b&gt; or code with &lt;b&gt;too many responsibilities&lt;/b&gt;.&lt;/li&gt;
                    &lt;li&gt; &lt;b&gt;Weak interfaces&lt;/b&gt; (with high probability to be changed):
                        &lt;ul&gt;
                            &lt;li&gt; Wrong level of abstraction.&lt;/li&gt;
                            &lt;li&gt; Responsibility smells.&lt;/li&gt;
                            &lt;li&gt; Data smells.&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/li&gt;
                &lt;/ul&gt;
            &lt;/li&gt;
            &lt;li&gt;A &lt;b&gt;misuse of test doubles&lt;/b&gt;, as we saw, &lt;b&gt;using&lt;/b&gt; them when we shouldn’t:
                &lt;ul&gt;
                    &lt;li&gt; the &lt;b&gt;misconception&lt;/b&gt; of &lt;b&gt;thinking the class is the unit&lt;/b&gt; (probably responsible of &lt;b&gt;most&lt;/b&gt; of the &lt;b&gt;mock-trauma&lt;/b&gt;).&lt;/li&gt;
                    &lt;li&gt; using &lt;b&gt;test doubles for value objects&lt;/b&gt;.&lt;/li&gt;
                    &lt;li&gt; using &lt;b&gt;test doubles for internals&lt;/b&gt;.&lt;/li&gt;
                    &lt;li&gt; using &lt;b&gt;test doubles for types we don’t own&lt;/b&gt;.&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/li&gt;
        &lt;/ol&gt;
    &lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;

&lt;p&gt;We think that instead of blaming test doubles, we need to learn to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Design better.&lt;/li&gt;
  &lt;li&gt;Use the tool better.&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2026-04-26T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/04/roots_of_the_mock_trauma_in_a_flash</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/04/roots_of_the_mock_trauma_in_a_flash</guid>
        </item>
      
    
      
        <item>
          <title>An Expensive Errand: Chasing 100% Mutation Coverage with an Agent Can Make Your Test Suite Worse</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;In this post, we walk through an experiment with AI-generated code and tests in order to explore the pitfalls of blindly using mutation testing to “improve” AI-generated test suites&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-code-and-tests-generated-by-the-coding-agent&quot;&gt;The code and tests generated by the coding agent.&lt;/h3&gt;

&lt;p&gt;We used a coding agent&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; to generate the code of a repository, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;, that gets discounts from a &lt;a href=&quot;https://mariadb.com/&quot;&gt;MariaDB&lt;/a&gt; database. This is the generated code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a1f96b6a0c29b67ab4585c3186f204c6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;To test it we prompted the agent with:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/4145616be596b15a28b504d160de4f30.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and the coding agent generated the following tests&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f40ba615caf5c3058040e0f299ce26b0.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;evaluating-the-ai-generated-tests-with-mutation-testing&quot;&gt;Evaluating the AI generated tests with mutation testing.&lt;/h2&gt;

&lt;p&gt;The generated tests initially looked reasonable, but, since we don’t trust AI-generated code, we ran mutation testing with &lt;a href=&quot;https://stryker-mutator.io/docs/stryker-js/introduction/&quot;&gt;StrykerJs&lt;/a&gt; in order to assess how good the tests were. We targeted only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; class and its tests to make the execution of &lt;a href=&quot;https://stryker-mutator.io/docs/stryker-js/introduction/&quot;&gt;StrykerJs&lt;/a&gt; faster.&lt;/p&gt;

&lt;p&gt;This was the resulting report:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/initial_mutants_report.png&quot; alt=&quot;Initial mutants report&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Initial mutants report.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There were 5 surviving mutants:&lt;/p&gt;

&lt;h3 id=&quot;m1&quot;&gt;M1&lt;a name=&quot;mutant_M1&quot;&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_1_in_initial_report.png&quot; alt=&quot;Surviving mutant M1&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M1.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;m2&quot;&gt;M2&lt;a name=&quot;mutant_M2&quot;&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_2_in_initial_report.png&quot; alt=&quot;Surviving mutant M2&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M2.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;m3&quot;&gt;M3&lt;a name=&quot;mutant_M3&quot;&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_3_in_initial_report.png&quot; alt=&quot;Surviving mutant M3&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M3.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;m4&quot;&gt;M4&lt;a name=&quot;mutant_M4&quot;&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_4_in_initial_report.png&quot; alt=&quot;Surviving mutant M4&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M4.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;m5&quot;&gt;M5&lt;a name=&quot;mutant_M5&quot;&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_5_in_initial_report.png&quot; alt=&quot;Surviving mutant M5&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M5.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;blindly-chasing-100-mutation-score-with-a-coding-agent&quot;&gt;Blindly chasing 100% mutation score with a coding agent.&lt;/h2&gt;

&lt;p&gt;It’s tempting to treat a mutation report like a checklist. Seeing those five survivors, we can think: “No problem, let’s tell the coding agent to just enhance the test suite until no mutant remains standing”. This is convenient and leverages AI’s speed to reach a 100% mutation score. Let’s see how this naive approach goes:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/prompt_to_kill_surviving_mutants.png&quot; alt=&quot;Prompt used to kill surviving mutants&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Prompt used to kill surviving mutants.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;At first glance, it looks like a victory. After a significant amount of time and burning some tokens&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;, the agent eventually managed to kill every single mutant. But, you’ll soon see, as we review the code, how this “convenient” approach created a maintenance headache.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/junie_all_mutants_killed.png&quot; alt=&quot;Summary shown by the agent after killing all mutants&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Summary shown by the agent after killing all mutants.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;To kill the surviving mutants the agent generated new test cases in the &lt;a href=&quot;https://gist.github.com/trikitrok/20bda13a0d915f5fa78544718d4f2c19&quot;&gt;integration tests&lt;/a&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;. It also generated &lt;a href=&quot;https://gist.github.com/trikitrok/2f73cb17e33c0596c67ce768dafdd1be&quot;&gt;unit tests&lt;/a&gt; (what?!? 😮):&lt;/p&gt;

&lt;p&gt;Let’s review them:&lt;/p&gt;

&lt;h3 id=&quot;the-new-version-of-the-integration-tests-of-mariadbdiscountsrepository&quot;&gt;The new version of the integration tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;.&lt;/h3&gt;

&lt;p&gt;Comparing the two versions of the integration tests we see that the agent modified one of the existing test cases, and added three new test cases.&lt;/p&gt;

&lt;p&gt;Let’s start with the modified existing test case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error when discount is not found&apos;&lt;/code&gt;:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/modified_existing_integration_test_case.png&quot; alt=&quot;Existing integration test case modified by the agent&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Existing integration test case modified by the agent.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The new version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error when discount is not found&apos;&lt;/code&gt; effectively kills the surviving mutant &lt;a href=&quot;#mutant_M2&quot;&gt;M2&lt;/a&gt;. However this test case is overspecified because it fixes the whole text of the exception message which makes it fragile to changes in the concrete error message. We think this may generate too much noise. Instead we should only specify the type of the exception and the discount code. At the end, we’ll show a refactored version of this test that removes this overspecification and still kills the mutant.&lt;/p&gt;

&lt;p&gt;These are the new three integration test cases added by the agent:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/148078afeebf0f6a278946cf981a874e.js&quot;&gt;&lt;/script&gt;

&lt;h4 id=&quot;new-test-case-1-should-throw-an-error-when-the-discount-type-is-unknown&quot;&gt;New test case 1: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error when the discount type is unknown&apos;&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This test case contains no assertions, just a comment saying that there is a DB constraint which prevents the discount type being unknown from happening. The comment also says that the related logic is fully covered in the unit tests, which is “smelly” and worrying, because the implementation of a repository should not be covered by unit tests, and the only way to write unit tests for it is by using test doubles for types we don’t own.&lt;/p&gt;

&lt;p&gt;This test case was meant to kill the surviving mutants &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; and &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt;. The agent wrote it in its first attempt to kill &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt;, but it failed because due to DB constraint discount type can’t be unknown. After several failed attempts, the agent decided to change its approach and still try to kill &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; writing unit tests full of test doubles… (we’ll review them later).&lt;/p&gt;

&lt;h4 id=&quot;new-test-case-2-should-handle-non-string-condition-data-correctly-eg-when-driver-already-parses-json&quot;&gt;New test case 2: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle non-string condition data correctly (e.g., when driver already parses JSON)&apos;&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This test case is redundant. It’s testing exactly the same as another already existing test case: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should find a percentage discount given its code&apos;&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;new-test-case-3-should-not-find-a-discount-if-the-query-filter-is-broken-killing-where-dcode---survivor&quot;&gt;New test case 3: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should not find a discount if the query filter is broken (killing WHERE d.code = ? survivor)&apos;&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This test case is useful. It kills the surviving mutant in the surviving mutant &lt;a href=&quot;#mutant_M1&quot;&gt;M1&lt;/a&gt;. Still, its name is bad and it has some overlap with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should find a percentage discount given its code&apos;&lt;/code&gt;. It would have been much better to modify that already existing test by adding two discounts to the DB in the initial fixture instead of only one.&lt;/p&gt;

&lt;p&gt;In summary, only two of the four changes generated by the coding agent in the integration tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; are actually improving the test suite:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The modified assertion in an already existing test case:  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error when discount is not found&apos;&lt;/code&gt; which kills the surviving mutant &lt;a href=&quot;#mutant_M2&quot;&gt;M2&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A new test case: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should not find a discount if the query filter is broken (killing WHERE d.code = ? survivor)&apos;&lt;/code&gt;  which kills the surviving mutant &lt;a href=&quot;#mutant_M1&quot;&gt;M1&lt;/a&gt;, although it would have been much better to modify the fixture of the previously existing test case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should find a percentage discount given its code&apos;&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The rest of the changes are noise or duplication.&lt;/p&gt;

&lt;h3 id=&quot;the-unit-tests-of-mariadbdiscountsrepository-&quot;&gt;The unit tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;… 😞.&lt;/h3&gt;

&lt;p&gt;These are the unit tests generated by the agent:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2f73cb17e33c0596c67ce768dafdd1be.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;A &lt;em&gt;huge red flag&lt;/em&gt; to notice is that the agent is &lt;strong&gt;using a test double of a type that we don’t own&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connection&lt;/code&gt;, which is part of &lt;a href=&quot;https://github.com/mariadb-corporation/mariadb-connector-nodejs&quot;&gt;mariadb&lt;/a&gt;, the &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node.js&lt;/a&gt; client library for connecting to a &lt;a href=&quot;https://mariadb.com/&quot;&gt;MariaDB&lt;/a&gt; database. Specifically, these unit tests are stubbing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connection&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using test doubles of types that we don’t own is a recipe for suffering&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;. This often hurts because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Our tests become tied to implementation details instead of outcomes which makes them utterly fragile.&lt;/li&gt;
  &lt;li&gt;Any changes in the interface of the type can break our tests.&lt;/li&gt;
  &lt;li&gt;The test double can drift away from real behavior.&lt;/li&gt;
  &lt;li&gt;We end up reimplementing the library’s behavior in our test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We should rely on integration tests to ensure our code talks to the database correctly; that is precisely the responsibility the integration tests were already fulfilling for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;.
Even in those rare cases where stubbing a method like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; might be necessary (for example, to trigger an exceptional behavior that is difficult to replicate in a real database) the agent should have at least introduced a thin wrapper around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connection&lt;/code&gt; to isolate the dependency. Instead, by using a test double for the library directly, the agent ignored a basic guideline and left us with tests that are tied to implementation details rather than outcomes.&lt;/p&gt;

&lt;p&gt;Having said this, let’s review the test cases to discuss what the intention of the agent was (which surviving mutant they were targeting) and whether they improve the test suite at all.&lt;/p&gt;

&lt;p&gt;There are six test cases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount is not found&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount type is unknown&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle non-string condition_data (e.g., when driver already parses it as object) and preserve the value&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle string condition_data correctly&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should distinguish between PERCENTAGE and FIXED types correctly&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should kill row.type === &quot;FIXED&quot; mutant by ensuring it throws when type is not FIXED even if it is the second condition&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of these six test cases, three are redundant because the behaviour they are checking is already covered by the integration tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount is not found&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle non-string condition_data (e.g., when driver already parses it as object) and preserve the value&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should distinguish between PERCENTAGE and FIXED types correctly&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can delete them, and still no mutants survive.&lt;/p&gt;

&lt;p&gt;Of the remaining three test cases, two are addressing the same surviving mutants, &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; and &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount type is unknown&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should kill row.type === &quot;FIXED&quot; mutant by ensuring it throws when type is not FIXED even if it is the second condition&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can delete one of them, and still no mutants survive.&lt;/p&gt;

&lt;p&gt;So only two of the six generated unit test cases were required for killing surviving mutants:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount type is unknown&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle string condition_data correctly&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s examine them in more detail&lt;/p&gt;

&lt;h4 id=&quot;non-redundant-test-case-should-throw-an-error-with-specific-message-when-discount-type-is-unknown&quot;&gt;Non redundant test case: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error with specific message when discount type is unknown&apos;&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This test case kills the surviving mutants, &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; and &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt;. However, a discount type in the database can’t be unknown because of a restriction in the definition of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;discounts&lt;/code&gt; table:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/890504846af6a1a99d482bf2ba4418ac.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONSTRAINT allowed_types CHECK (type IN (&apos;FIXED&apos;, &apos;PERCENTAGE&apos;))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The agent is using a stub to return something that can’t be in the database, in order to kill a surviving mutant. This test case is not improving the test suite at all, in fact, it’s making it worse, because it’s not only coupling the tests to a type we don’t own, but also “ossifying” an implementation detail that is unnecessary. We’ll explain this when we analyze the relevant mutants in the next section.&lt;/p&gt;

&lt;h4 id=&quot;non-redundant-test-case-should-handle-string-condition_data-correctly&quot;&gt;Non redundant test case: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should handle string condition_data correctly&apos;&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This test case kills the surviving mutant &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt;. However, the data of a condition in the database can’t be a string because of how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;discount_conditions&lt;/code&gt; table is defined:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/65039793b47ec93c6dc660b3e0abafc7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The data of a condition returned by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; method will always be an object.&lt;/p&gt;

&lt;p&gt;Again, the agent is using a stub to return something that can’t be in the database, in order to kill a surviving mutant. Like in the previous case, this test case is making the test suite worse (for the same reasons).&lt;/p&gt;

&lt;h4 id=&quot;conclusion-the-generated-unit-tests-were-useless&quot;&gt;Conclusion: the generated unit tests were useless.&lt;/h4&gt;

&lt;p&gt;We’ve seen how the only two test cases that weren’t redundant, were actually making our test suite harder to maintain (by coupling to types we don’t own) and “ossifying” unnecessary implementations.&lt;/p&gt;

&lt;p&gt;You may ask: “how are we going to kill the surviving mutants, &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt;, &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; and &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt; then?”&lt;/p&gt;

&lt;p&gt;The answer is that &lt;strong&gt;we won’t kill them with tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s delete those unit tests and examine the surviving mutants, &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt;, &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; and &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt; using the idea of &lt;strong&gt;relevant mutants&lt;/strong&gt;&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;going-back-and-analyzing-which-mutants-are-relevant-first&quot;&gt;Going back and analyzing which mutants are relevant first.&lt;/h2&gt;

&lt;p&gt;Instead of blindly asking the agent to “improve” the test suite to kill mutants, a better approach would have been examining each surviving mutant first to see if it’s a &lt;em&gt;relevant mutant&lt;/em&gt; or not.&lt;/p&gt;

&lt;h3 id=&quot;relevant-mutants&quot;&gt;Relevant Mutants.&lt;/h3&gt;

&lt;p&gt;Not all surviving mutants indicate weaknesses in the tests suite: they are not relevant for improving the test suite.&lt;/p&gt;

&lt;p&gt;Surviving mutants that don’t signal problems in the tests suite may survive because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They are in dead code (unreachable code).&lt;/li&gt;
  &lt;li&gt;They are part of legacy seams, and thus intentionally excluded from test execution.&lt;/li&gt;
  &lt;li&gt;They are part of code only that is only used by code in legacy seams. This exclusion from test execution is also intentional.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another kind of surviving mutants that don’t signal weaknesses in the tests suite, are mutants which are in &lt;strong&gt;superfluous code&lt;/strong&gt;. Even though they are in reachable code that is exercised by the tests suite, they survive because the mutation does not change any behavior. These mutants are still useful because they signal a possible simplification: a refactoring opportunity.&lt;/p&gt;

&lt;h3 id=&quot;analyzing-the-surviving-mutants-in-mariadbdiscountsrepository-using-the-idea-of-relevant-mutants&quot;&gt;Analyzing the surviving mutants in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; using the idea of Relevant Mutants.&lt;/h3&gt;

&lt;p&gt;Only &lt;a href=&quot;#mutant_M1&quot;&gt;M1&lt;/a&gt; and &lt;a href=&quot;#mutant_M2&quot;&gt;M2&lt;/a&gt; were relevant to improve our test suite: they were signalling problems in the test suite like missing boundaries, too lenient assertions, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;#mutant_M1&quot;&gt;M1&lt;/a&gt; was signalling a missing boundary. The original generated tests were using fixtures with only one discount, and checking that they were finding it, so no wonder we didn’t need to check its code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where&lt;/code&gt; clause.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_1_in_initial_report.png&quot; alt=&quot;Surviving mutant M1&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M1.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;#mutant_M2&quot;&gt;M2&lt;/a&gt; was signalling a too lenient assertion. The test case in the original test suite was just checking the type of the exception that the repository threw, so the mutation testing tool could remove the exception message without breaking any test.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_2_in_initial_report.png&quot; alt=&quot;Surviving mutant M2&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M2.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The agent did a better job with these two mutants because they really were meant to be killed by improving the test suite. Although it still didn’t do it too well (overspecifying in one case and overlapping test cases in another).&lt;/p&gt;

&lt;p&gt;On the contrary, &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt;, &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; and &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt; were not signalling problems in the test suite. They are signalling code that can be removed without changing the behaviour because it’s either &lt;strong&gt;superfluous&lt;/strong&gt; or &lt;strong&gt;unreachable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; was signalling &lt;strong&gt;superfluous code&lt;/strong&gt;. Remember that the type of discount in the database can only be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PERCENTAGE&lt;/code&gt; or ‘FIXED’, so if the type is not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FIXED&lt;/code&gt;, it can only be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PERCENTAGE&lt;/code&gt; that makes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else if (row.type === ‘FIXED’)&lt;/code&gt; superfluous (it’s always true).&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_3_in_initial_report.png&quot; alt=&quot;Surviving mutant M3&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M3.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; was surviving because that branch is &lt;strong&gt;unreachable&lt;/strong&gt;. Again, if the type of discount in the database can only be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PERCENTAGE&lt;/code&gt; or ‘FIXED’, there is no integration test that can exercise code in that branch.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_4_in_initial_report.png&quot; alt=&quot;Surviving mutant M4&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M4.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt; and &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; should be killed by refactoring, not testing. We can simplify the implementation and keep the same behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; by substituting that conditional code by this other one with no surviving mutants&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/bc7cbacf5fad77d2326d29ba948b3a43.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Regarding &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt;, this surviving mutant was also signalling &lt;strong&gt;superfluous code&lt;/strong&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/coding-agent-killing-mutants/mutant_5_in_initial_report.png&quot; alt=&quot;Surviving mutant M5&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutant M5.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Since the type of the data of a condition in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;discount_conditions&lt;/code&gt; table is defined as a JSON field, it will never be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt;. That’s why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typeof row.condition_data === string&lt;/code&gt; can be mutated to false without changing the behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt; should be killed by refactoring, not testing. We can simplify the implementation and keep the same behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; by removing the whole ternary Operator (? :):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/fdffe5aada558aff7444db7d8a0d3b02.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is the code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MariaDBDiscountsRepository&lt;/code&gt; after applying two simplifications:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5c8482cdf614afe3ee6491fadbea7f89.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the final version of the tests that kill all the relevant mutants:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/78cee042fab4400e7634702fa9f0932a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how we have managed to kill &lt;a href=&quot;#mutant_M2&quot;&gt;M2&lt;/a&gt; while at the same time avoiding overspecifying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;should throw an error when discount is not found&apos;&lt;/code&gt; by asserting the exception type and that the exception message contains the non-existing discount code (the only part of the message we care about), instead of asserting the exception type and the whole exception message. That way the “literature” around the discount code can change without breaking our test.&lt;/p&gt;

&lt;h3 id=&quot;learnings-from-relevant-mutants&quot;&gt;Learnings from Relevant Mutants.&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Not all surviving mutants need to be killed: Those in legacy seams or in code only used by code in legacy seams survive because that code is intentionally not exercised by the tests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Not all surviving mutants that need to be killed should be killed by testing “better”, some should be killed by refactoring (simplifying superfluous code or deleting dead code).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this example, we should have never asked the agent to kill &lt;a href=&quot;#mutant_M3&quot;&gt;M3&lt;/a&gt;, &lt;a href=&quot;#mutant_M4&quot;&gt;M4&lt;/a&gt; and &lt;a href=&quot;#mutant_M5&quot;&gt;M5&lt;/a&gt; by “improving” the test suite in the first place. The result of having done it was a much harder-to-maintain test suite and “ossifying” unnecessary behaviour with tests.&lt;/p&gt;

&lt;p&gt;Unless we’re able to teach our coding agents to discern between these kinds of surviving mutants, I think we should stay in the loop to help them.&lt;/p&gt;

&lt;p&gt;In a future post, we’ll show a better way to give feedback to coding agents when using mutation testing.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;In this experiment, we used a coding agent to generate both the implementation of a repository and its tests, then used mutation testing to evaluate the suite. Our goal was to illustrate the pitfalls of a workflow we find worrying: treating mutation testing as a mechanical way to “improve” AI-generated tests without humans in the loop. The initial tests looked reasonable, but once mutation testing exposed several surviving mutants, we deliberately followed the naive path: just asking the agent to eliminate them all.&lt;/p&gt;

&lt;p&gt;The result was exactly what we expected. We reached a 100% mutation score, but the agent got there by introducing a mix of overspecified assertions, duplicated coverage, and tests for scenarios that can’t actually occur given the database constraints. It even generated unit tests that used test doubles for types we don’t own, tightly coupling the tests to implementation details. On paper, the metrics improved; in practice, the test suite became more fragile.&lt;/p&gt;

&lt;p&gt;When we reviewed the generated tests carefully, we saw that only a small subset addressed real weaknesses in the test suite. Some surviving mutants, known as &lt;a href=&quot;https://codesai.com/posts/2024/07/relevant-mutants&quot;&gt;relevant mutants&lt;/a&gt;, were useful signals pointing to missing boundaries or weak assertions, and improving or adding tests to kill them made sense. But other surviving mutants weren’t related to test problems at all. They were symptoms of unreachable or superfluous code: cases where the implementation could be simplified without changing behavior. For those, adding tests didn’t improve confidence; it just entrenched unnecessary complexity. To fix the mess produced by the naive approach, we deleted the unit tests generated by the agent and “killed” these latter mutants by refactoring and simplifying the production code. By removing the superfluous logic, we ended up with a simpler implementation of the repository and a more maintainable test suite.&lt;/p&gt;

&lt;p&gt;The point of this exercise is to show that blindly prompting a coding agent to enhance a test suite until all mutants are killed is a mistake. It is an approach that risks wasting a lot of tokens in the process to get a less maintainable test suite. Not all mutants are worth killing with tests, and treating a mutation report as a checklist for an agent encourages overfitting and brittle design. Our experience suggests that we must remain in the loop to discern how to treat each surviving mutant; leaving that judgment entirely to a coding agent is a risky and expensive practice.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/fernandoaparicio/&quot;&gt;Fernando Aparicio&lt;/a&gt;, and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/@pavel-danilyuk/&quot;&gt;Pavel Danilyuk&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2024/07/relevant-mutants&quot;&gt;Relevant Mutants&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/relevant_mutants_in_a_flash&quot;&gt;Relevant Mutants in a Flash&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://testing.googleblog.com/2020/07/testing-on-toilet-dont-mock-types-you.html&quot;&gt;Testing on the Toilet: Don’t Mock Types You Don’t Own&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stefan-kennedy-65b128105/&quot;&gt;Stefan Kennedy&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/andrewtrenk/&quot;&gt;Andrew Trenk&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] We used an example from one of the sessions of the deliberate practice program we have been running for &lt;a href=&quot;https://www.audiense.com/&quot;&gt;Audiense&lt;/a&gt;’s developers since 2022.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] In the deliberate practice session, we used TDD rather than AI agents to develop the repository. These sessions are designed with two goals in mind:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Keep fundamental engineering skills strong, avoiding &lt;a href=&quot;https://addyo.substack.com/p/avoiding-skill-atrophy-in-the-age&quot;&gt;skill atrophy induced by AI&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Introduce new technical practices and ideas to the team on a continuous basis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] We actually extracted a helper method with our IDE to improve the readability of the generated tests.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] We think, it is important to note that, as shown in the review of the tests, we consumed a significant amount of tokens chasing a goal that was fundamentally misguided. Because the agent lacked the context to see that some mutants were simply signalling unreachable or superfluous code, it spent expensive cycles trying to ‘kill’ with tests, mutants that should have been refactored away or ignored. With just a moment of human feedback, we could have avoided this expensive errand and focused the AI on the mutants that actually mattered. Instead, we didn’t just waste tokens; we effectively paid to introduce technical debt in the form of fragile, coupled unit tests.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5]  Several good sources to understand why using test doubles for types you don’t own is a bad idea:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Subsection &lt;em&gt;4.1 Only Mock Types You Own&lt;/em&gt; of section &lt;em&gt;4. Mock Objects in Practice&lt;/em&gt; of paper  &lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;. Probably the original source of the idea.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Section &lt;em&gt;Only Mock Types That You Own&lt;/em&gt; from chapter 8 of &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS book&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The post &lt;a href=&quot;https://testing.googleblog.com/2020/07/testing-on-toilet-dont-mock-types-you.html&quot;&gt;Testing on the Toilet: Don’t Mock Types You Don’t Own&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] You can read about this idea in these two posts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2024/07/relevant-mutants&quot;&gt;Relevant Mutants&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/relevant_mutants_in_a_flash&quot;&gt;Relevant Mutants in a Flash&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] In Spanish we say: “muerto el perro se acabó la rabia” 😅&lt;/p&gt;

</description>
          <pubDate>2026-04-21T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/04/agents-blindly-killing-mutants</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/04/agents-blindly-killing-mutants</guid>
        </item>
      
    
      
        <item>
          <title>Refactoring with AI: Introducing a State Pattern using a coding agent</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;This is a snapshot of an intermediate step of a kata we use to practise &lt;a href=&quot;https://www.geeksforgeeks.org/software-testing/specification-based-testing/&quot;&gt;specification testing&lt;/a&gt; and test doubles&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e718d90eb2af18e1507e2833e1da245f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class presents a case of the &lt;a href=&quot;https://codesai.com/posts/2025/12/simple-temporary-field-example#temporary_field_definition&quot;&gt;temporary field&lt;/a&gt; code smell, which occurs when a field is set only at certain times and is null or unused at other times, making the object harder to understand and maintain. This is what happens with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startTime&lt;/code&gt; field which is implicitly set to null until the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt; method gets called. As usual, the temporary field comes with a &lt;a href=&quot;https://luzkan.github.io/smells/null-check&quot;&gt;null check code smell&lt;/a&gt; which is avoiding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NullPointerException&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;computeMinutesBetween&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;As we’ve seen in previous posts&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;, a temporary field may indicate a deeper design issue. In this case the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class is representing three different states of a course:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;A course that has not started yet&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;An ongoing course&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;A finished course&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can remove both the temporary field and the null check code smells by introducing a &lt;a href=&quot;https://en.wikipedia.org/wiki/State_pattern&quot;&gt;state design pattern&lt;/a&gt; that explicitly models this state machine and removes conditional code.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/course_state_machine.png&quot; alt=&quot;Course state machine diagram.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Course state machine diagram.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Introducing the state design pattern is an involved refactoring that comprises extracting new classes, introducing polymorphism and moving behaviour around. We’ll show how we can accelerate it with the help of an AI coding agent.&lt;/p&gt;

&lt;h2 id=&quot;refactoring-to-the-state-design-pattern-with-an-ai-agent&quot;&gt;Refactoring to the state design pattern with an AI agent.&lt;/h2&gt;

&lt;p&gt;I passed the following prompt to the &lt;a href=&quot;https://github.com/features/copilot/cli&quot;&gt;copilot cli agent&lt;/a&gt; using the &lt;a href=&quot;https://www.anthropic.com/claude/sonnet&quot;&gt;Claude Sonnet 4.6&lt;/a&gt; model with the default thinking effort (balanced, thinks on harder problems).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Let’s introduce a state pattern.&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class will keep its current interface.&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; will use an abstract class of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; that will represent its state.&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; is an abstract class with the following public methods: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void showDetails()&lt;/code&gt;, &amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState start()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState end()&lt;/code&gt;, of which start and end are abstract.&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; is going to be derived by three concrete states:&lt;/p&gt;

  &lt;p&gt;Concrete classes representing states:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;: This is the initial state of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt;.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;: Pass its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startTime&lt;/code&gt; through its constructor: new OnGoingCourseState(startTime, clock, configuration, courseView).&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;: Pass its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;durationInMinutes&lt;/code&gt; through its constructor: new FinishedCourseState(durationInMinutes, clock, configuration, courseView).&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Initial state: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;Final state: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;Possible transitions:&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;  —-start()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;  —-end()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;  —-start()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;  —-end()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;  —-start()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;  —-end()—-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent generated the following new classes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; is an abstract class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/30ad3d02fe9826dbd8b4f66fcb836fb0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And the state classes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt; derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/4b9147d8c2859f421b87778b489891a9.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0b136c2c371d4e69a7207beeb593dd3e.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/b4640e107a04bcaad05fc1ede06cbda8.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This the resulting code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class that delegates all its operations to its inner state:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/002fbcb1d3de7a11bbd8367e78492b2c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We can consider this transformation a refactoring because:&lt;/p&gt;

&lt;p&gt;a. It preserved observable behaviour: all tests still passed after it, and
b. It improved maintainability: both the temporary field and null check code smells were removed.&lt;/p&gt;

&lt;p&gt;The agent did a great job introducing the state design pattern, and it did it in less time than what it had taken me to refactor it using the IDE (&lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt; in this case).&lt;/p&gt;

&lt;h3 id=&quot;using-our-metadocumentation-to-learn&quot;&gt;Using our metadocumentation to learn.&lt;/h3&gt;

&lt;p&gt;Let’s have a look at the &lt;a href=&quot;https://codesai.com/posts/2026/03/metadocumenting-ai-agents-work&quot;&gt;metadocumentation generated by the agent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reasoning document is very interesting:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c6034d5e333d5e4f45e03fb1a1687e43.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Even though the agent does not mention the temporary field code smell, it describes the initial design saying that &lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; managed its lifecycle internally using nullable fields&lt;/em&gt; and having a &lt;em&gt;null-check to distinguish “not yet started” from other states&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The alternatives that it considered and then rejected are also very interesting to me, and I agree with all its decisions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Override &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showDetails()&lt;/code&gt; in each concrete state&lt;/strong&gt;, which would have created duplication that we would have had to remove with a &lt;a href=&quot;https://refactoring.guru/pull-up-method&quot;&gt;Pull Up Method&lt;/a&gt; refactoring.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Keep &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; only in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt;, pass it on each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showDetails()&lt;/code&gt; call&lt;/strong&gt;, which is really not necessary.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Make transitions a lookup table / enum&lt;/strong&gt;, which would have been over-engineering for only three states.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was the feedback the agent gave me on my prompt:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/be4423f43dae0e52afd766f0b0dddc18.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;It states that giving it a transition table was the most valuable part of the prompt, and advises me to do it in future prompts that ask to introduce state machines.&lt;/p&gt;

&lt;p&gt;Two other things that were useful were telling it to preserve the interface of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; which eliminated many options to explore, and specifying the parameters of each constructor which clarified the intent of each state.&lt;/p&gt;

&lt;p&gt;In the prompt I forgot to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; as a parameter of the constructors of the state classes. I didn’t realize that until I read the feedback. In spite of that, the agent realized that that was a mistake and that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; needed to be passed as a parameter to all the constructors.&lt;/p&gt;

&lt;p&gt;The three other gaps in the prompt were things I considered obvious. They were not a problem using the &lt;a href=&quot;https://github.com/features/copilot/cli&quot;&gt;copilot cli agent&lt;/a&gt; with the &lt;a href=&quot;https://www.anthropic.com/claude/sonnet&quot;&gt;Claude Sonnet 4.6&lt;/a&gt; model, but they may have been problematic using a different combination of agent and model&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My learning is that some things that are obvious to me may not be so for the model, and that If I had any doubts that it can handle some expectation by default, I should at least make that expectation explicit. Additions like “&lt;em&gt;classes should not have any unused fields after the transformation&lt;/em&gt;“&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. or “&lt;em&gt;give methods the least visibility possible&lt;/em&gt;” may have proved useful in this case.&lt;/p&gt;

&lt;p&gt;Finally, this is the enhanced summary created by the agent:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/07dbb05d867b1ad14a4d60743e2a3eeb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In the &lt;strong&gt;Side effects / follow-up&lt;/strong&gt; section, there’s a very useful piece of advice that I plan to follow, saying that I need to change the configuration of  the mutation testing tool in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt; so that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targetClasses&lt;/code&gt; covers not only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class but also all the new state classes.&lt;/p&gt;

&lt;h2 id=&quot;improving-the-design-a-bit-more&quot;&gt;Improving the design a bit more.&lt;/h2&gt;

&lt;p&gt;I was very satisfied with the code that the agent generated. However, there is something that I think could have been better: in order to avoid possible cases of the &lt;a href=&quot;https://wiki.c2.com/?InappropriateIntimacy&quot;&gt;inappropriate intimacy&lt;/a&gt; code smell, I’d prefer that all the fields in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; were &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the current design they have to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected&lt;/code&gt; because they are being used in some derived class to pass them to constructors when there are state transitions.&lt;/p&gt;

&lt;p&gt;If we introduced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected&lt;/code&gt; factory methods representing the state transitions, the fields could become &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt;. The factory methods would also improve the semantics of the code.&lt;/p&gt;

&lt;h3 id=&quot;refactoring-with-an-agent-or-using-intellij&quot;&gt;Refactoring with an agent or using IntelliJ?&lt;/h3&gt;

&lt;p&gt;The refactoring to introduce those &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected&lt;/code&gt; factory methods is not very involved if we use an IDE like &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt;. With this IDE, we only need to chain two automated refactorings for the state transition from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;, and three automated refactorings for the state transition from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These chains of automated refactorings are detailed in the following table:&lt;/p&gt;

&lt;table class=&quot;zebraTable&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Transition&lt;/th&gt;
      &lt;th&gt;Chain of Automated Refactorings&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;YetToStart -&amp;gt; OnGoing&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.jetbrains.com/help/idea/extract-method.html&quot;&gt;Extract Method&lt;/a&gt; -&amp;gt; &lt;a href=&quot;https://www.jetbrains.com/help/idea/pull-members-up.html&quot;&gt;Pull Up Method refactoring&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;OnGoing -&amp;gt; Finished&lt;/td&gt;
      &lt;td&gt;&lt;a href=&quot;https://www.jetbrains.com/help/idea/extract-variable.html&quot;&gt;Introduce Variable&lt;/a&gt; -&amp;gt; &lt;a href=&quot;https://www.jetbrains.com/help/idea/extract-method.html&quot;&gt;Extract Method&lt;/a&gt; -&amp;gt; &lt;a href=&quot;https://www.jetbrains.com/help/idea/pull-members-up.html&quot;&gt;Pull Up Method refactoring&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;I felt that using an agent for this refactoring would not be more efficient than using the automated refactorings in the IDE, even considering that the &lt;a href=&quot;https://refactoring.guru/pull-up-method&quot;&gt;Pull Up Method refactoring&lt;/a&gt; does not have a default shortcut associated with it in &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt; (which is fine because we don’t use this refactoring so often).&lt;/p&gt;

&lt;p&gt;In order to test my gut feeling, I decided to do the following experiment:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Measure the time it takes me to refactor to the desired design with &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Revert the change.&lt;/li&gt;
  &lt;li&gt;Measure the time it takes me to write the prompt and the agent to process it (I didn’t include the time it took the agent to generate the metadocumentation which happens at the end).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the result of the experiment:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Using automatic refactorings in &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt;: 4’.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;With the agent (prompt writing + agent execution): 7’.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My intuition was right, it was shorter to refactor it myself using &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re curious about the prompt I used, here it is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want to make all the fields in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; private.
To do that first extract to method the state transition in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnGoingCourseState&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;end()&lt;/code&gt; method to a method accepting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startTime&lt;/code&gt; as a parameter and the state transition in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YetToStartCourseState&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start()&lt;/code&gt; method,
then pull both methods up to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt;.&lt;/p&gt;

  &lt;p&gt;After your changes all tests should be still passing and all fields in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; should be private.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also attached to the prompt the four course state classes.&lt;/p&gt;

&lt;p&gt;The agent got to a final design that was exactly like mine. In fact, I think the names it gave to the factory methods were better than mine. You can check the &lt;a href=&quot;https://gist.github.com/trikitrok/a7ab4f9c195bff9de05a2306c6a0e1b9&quot;&gt;final code of the state hierarchy in this gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think that asking an agent to do a small refactoring like this one, that can be made with a short chain of automatic IDE refactorings, would have been fine for me only if I let the agent do it autonomously while I have a break.&lt;/p&gt;

&lt;p&gt;Some people would say that I could have worked on another task while the agent was working, but there are two reasons I prefer not to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Seven minutes is not too long, and switching contexts take some time.&lt;/li&gt;
  &lt;li&gt;We already know that multitasking is not good for anyone’s brain nor productivity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My current aspiration is getting to an approach to AI similar to what &lt;a href=&quot;https://mitchellh.com/&quot;&gt;Mitchell Hashimoto&lt;/a&gt; describes in &lt;a href=&quot;https://mitchellh.com/writing/my-ai-adoption-journey&quot;&gt;My AI Adoption Journey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another advantage of automatic IDE refactorings is that they are deterministic and tend to be safe&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I prefer to use an agent for refactorings in which there’s really a speed boost, so that taking the risk of assuming possible reworks associated with non-determinism is still worth it.&lt;/p&gt;

&lt;h3 id=&quot;using-our-metadocumentation-to-learn-1&quot;&gt;Using our metadocumentation to learn.&lt;/h3&gt;

&lt;p&gt;Let’s start with the reasoning file:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/96fe85ce5ed789c9660586bdc4c31436.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In the reasoning, we can see that the agent followed the process outlined in the prompt. I wonder whether the agent would still be able to produce correct code if the prompt were more vague and required less effort to write (I may test this in the future).&lt;/p&gt;

&lt;p&gt;If we have a look at the alternatives the agent considered and rejected, I’m satisfied of its decisions and the reasons why it took them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add getters instead of pulling up methods&lt;/strong&gt;, this option would have achieved the goal of making the fields private, but as the agent says “would expose the fields indirectly and leave transition logic scattered”. It rejected this option because “it moves in the wrong direction for encapsulation”, which I think is totally right. I also prefer a &lt;a href=&quot;https://martinfowler.com/bliki/TellDontAsk.html&quot;&gt;tell don’t ask&lt;/a&gt; approach.&lt;/p&gt;

&lt;p&gt;I think this option would have  probably been accepted if I had written a more vague prompt like:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want the fields in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; to be private. Make the changes in the state classes to make it possible without altering its public interface. All tests should pass after your changes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Keep fields &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected final&lt;/code&gt;&lt;/strong&gt;: the agent says that this option is “simpler but weaker encapsulation” which is true. What I like is the reason why it rejects it: because rejecting it is “in favour of the user’s stated goal”.&lt;/p&gt;

&lt;p&gt;I don’t like its reasoning simply because the agent followed my suggestion; instead, I like it because, in this simple case, it’s true that encapsulating the fields offers little advantage. I think the agent is indirectly recognizing that we may be trading simplicity for insufficient benefits, since the signal of the &lt;a href=&quot;https://wiki.c2.com/?InappropriateIntimacy&quot;&gt;inappropriate intimacy code smell&lt;/a&gt; is currently very weak.&lt;/p&gt;

&lt;p&gt;Let’s see now the feedback about my prompt:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/970323ad72e8ad83425721ff177bdb45.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Of the three improvement suggestions, I think the most valuable to me is the one about clarifying the visibility of the pulled-up methods.&lt;/p&gt;

&lt;p&gt;I don’t care about the suggestion about unused-import cleanup because that is something I can automatically and deterministically do with other tools at the end or in a hook. Why make the agent spend time and tokens on something that is solved cheaper, faster and safer by other existing tools? The &lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/patterns/offload-deterministic/&quot;&gt;Offload Deterministic&lt;/a&gt; augmented coding patterns states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Don’t ask AI to do deterministic work. Ask AI to write code that does it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think that, when a reliable deterministic tool already exists and is available, we are better off applying an extension of the &lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/patterns/offload-deterministic/&quot;&gt;Offload Deterministic&lt;/a&gt; pattern:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Don’t ask AI to do deterministic work for which a deterministic tool already exists. Use the tool if available; otherwise, ask AI to write code that does it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Regarding the suggestion about naming, in this case, I was very confident that the agent would get the naming right, given the names of the constructors mentioned in the prompt and that I was stating that the methods were factories. However, in other not so clear-cut cases, I think I would follow its suggestion. In any case, renaming is often safe and easy in most IDEs.&lt;/p&gt;

&lt;p&gt;If you feel like, you can check &lt;a href=&quot;https://gist.github.com/trikitrok/cb222d8cb82ee867c6e8f8540264d6d1&quot;&gt;the summary file in this gist&lt;/a&gt;, for completeness sake.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h2&gt;

&lt;p&gt;In this post, we’ve explored using a coding agent to introduce the &lt;a href=&quot;https://en.wikipedia.org/wiki/State_pattern&quot;&gt;state design pattern&lt;/a&gt; into an existing design that was implicitly handling multiple states. By making those states explicit, we moved from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; class with a temporary field and null checks code smells to a clearer design based on polymorphism and explicit state classes.&lt;/p&gt;

&lt;p&gt;We prompted the agent, describing the state transitions of the desired state machine and some constraints, and let the agent carry out the bulk of the transformation: extracting state classes, redistributing behaviour, and removing conditional logic. The result was a design that better reflected the domain, with each state owning its responsibilities and transitions.&lt;/p&gt;

&lt;p&gt;Looking at the agent’s &lt;a href=&quot;https://codesai.com/posts/2026/03/metadocumenting-ai-agents-work&quot;&gt;metadocumentation&lt;/a&gt; gave us additional value beyond the code itself. It helped us understand how the agent interpreted the problem, what alternatives it considered, and how our prompt shaped the outcome. One clear takeaway was that being explicit, especially about transitions and invariants, can make a noticeable difference in the quality of the result.&lt;/p&gt;

&lt;p&gt;We also iterated on the design after the initial refactoring, improving encapsulation in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; and introducing factory methods for transitions. That step served to perform an experiment that compared approaches: while the agent was capable of performing the refactoring, traditional IDE-supported transformations proved faster and more predictable in this case.&lt;/p&gt;

&lt;p&gt;We used the introduction of the state pattern to explore how and when a coding agent can help with structural refactorings. Our experience suggests a balanced approach: rely on the agent when it meaningfully accelerates complex changes, and lean on deterministic tools when they provide a simpler path.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/fernandoaparicio/&quot;&gt;Fernando Aparicio&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt;
for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@maxwell-pels-1372108218/&quot;&gt;Maxwell Pels&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/patterns/offload-deterministic/&quot;&gt;Offload Deterministic&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/lada-kesseler/&quot;&gt;Lada Kesseler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://mitchellh.com/writing/my-ai-adoption-journey&quot;&gt;My AI Adoption Journey&lt;/a&gt;, &lt;a href=&quot;https://mitchellh.com/&quot;&gt;Mitchell Hashimoto&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/03/metadocumenting-ai-agents-work&quot;&gt;Metadocumenting to Improve Our Interactions with Coding Agents: Capturing Reasoning, Summaries, and Prompt Feedback&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] This code is a snapshot of an intermediate step of the &lt;a href=&quot;https://github.com/Codesai/testing-training-java/tree/main/course-duration&quot;&gt;Course Duration kata&lt;/a&gt; which is part of our training in testing techniques for developers. You can find the contents of the Spanish version in &lt;a href=&quot;https://codesai.com/cursos/testing-techniques/&quot;&gt;Técnicas de Testing para desarrolladores&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] The posts we refer to are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/12/simple-temporary-field-example&quot;&gt;A simple example of the temporary field code smell&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2024/03/using-smells-to-go-oo&quot;&gt;Using code smells to refactor to more OO code (an example with temporary field, solution sprawl and feature envy)&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] We tried using the same prompt with &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt; using &lt;a href=&quot;https://deepmind.google/models/gemini/flash/&quot;&gt;Gemini 3 Flash&lt;/a&gt; with very different results.&lt;/p&gt;

&lt;p&gt;We didn’t like the resulting code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It left some dead code (getters for the dependencies), unused fields for the dependencies (only used in the unused getters) and setters in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; (to set the duration of the course).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It set a reference to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Course&lt;/code&gt; into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CourseState&lt;/code&gt; using an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attach&lt;/code&gt; method that was called right after creating each instance of the course state.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It left several useless &lt;a href=&quot;https://luzkan.github.io/smells/what-comment&quot;&gt;“what” comments&lt;/a&gt; in the course state classes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It left an unused field in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FinishedCourseState&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can have a look at the code in &lt;a href=&quot;https://gist.github.com/trikitrok/f632d82c6f7e70ce1c7609becd1f72c4&quot;&gt;this gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In a future experiment, we plan to try the improved version of the prompt with  &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt; and &lt;a href=&quot;https://deepmind.google/models/gemini/flash/&quot;&gt;Gemini 3 Flash&lt;/a&gt; to see if we get better results.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] As we mentioned in the previous note, &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt; using &lt;a href=&quot;https://deepmind.google/models/gemini/flash/&quot;&gt;Gemini 3 Flash&lt;/a&gt; generated exactly this problem.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] At least in Java and C#, though not always in dynamic languages.&lt;/p&gt;

</description>
          <pubDate>2026-04-10T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/04/ai-refactor_to_state</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/04/ai-refactor_to_state</guid>
        </item>
      
    
      
        <item>
          <title>Detallando historias de usuario para acotarlas y reducir su ambigüedad.</title>
          <description>&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;
&lt;p&gt;En un &lt;a href=&quot;https://codesai.com/posts/2025/10/flujo-refinar-hu-en-tc&quot;&gt;post anterior&lt;/a&gt;, exploramos nuestro flujo de decisión para refinar historias de usuario poco antes de iniciar su desarrollo. Allí vimos cómo utilizar los criterios &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt; para diagnosticar si una historia ya está lista para ser desarrollada y así evitar retrabajo. El principal objetivo de nuestro proceso es aplicar refinamientos específicos que aseguren un desarrollo fluido, minimizar el &lt;em&gt;waste&lt;/em&gt; y acelerar la entrega de valor.&lt;/p&gt;

&lt;p&gt;También vimos que algunos incumplimientos tanto del criterio de Estimable (E) como del criterio de Testable (T), pueden producirse porque la historia no esté suficientemente acotada o aclarada. Comentamos que ambos casos se podrían solucionar &lt;strong&gt;añadiendo más detalle&lt;/strong&gt;, y dejamos para otro post la explicación de cómo detallar mejor una historia.&lt;/p&gt;

&lt;p&gt;En este post profundizaremos en &lt;strong&gt;cómo detallar una historia de usuario&lt;/strong&gt; mediante criterios de aceptación y ejemplos que nos ayudarán a que todo el equipo tenga una visión común de lo que significa que la historia quede realmente “hecha”.&lt;/p&gt;

&lt;h2 id=&quot;añadir-más-detalle&quot;&gt;Añadir más detalle.&lt;/h2&gt;

&lt;p&gt;Antes de empezar a explicar este proceso, nos gustaría recalcar que no hay que añadir todo el detalle posible a una historia de usuario de golpe, de hecho esto podría ser contraproducente ya que podría ocasionar &lt;em&gt;waste&lt;/em&gt;. Es más aconsejable detallar las historias de usuario de forma incremental.&lt;/p&gt;

&lt;p&gt;Los detalles acotan y aclaran los límites de la historia&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. Esto permite que todos los participantes empiecen a tener una visión compartida sobre el tamaño de la historia y todos los comportamientos que se esperan de ella.&lt;/p&gt;

&lt;p&gt;Durante el proceso de &lt;strong&gt;añadir detalle&lt;/strong&gt;, se hace más evidente lo que se espera de la historia, y esto puede hacer que nos planteemos si podría ser mejor hacer ciertas partes en otra historia (o directamente descartarlas). Así, el proceso de añadir más detalle puede llevarnos a evaluar el criterio Small (S) para plantearnos si hay algún tipo de partición que pueda ser beneficioso&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Este ciclo de &lt;strong&gt;añadir detalle&lt;/strong&gt; y evaluar el criterio Small antes de continuar haciendo crecer la historia, es fundamental para entregar de manera incremental y no generar &lt;em&gt;waste&lt;/em&gt; haciendo trabajo innecesario.&lt;/p&gt;

&lt;p&gt;Justo antes de empezar a desarrollarla, acabar de completar el detalle de una historia ayuda a que todas las personas del equipo estén alineadas en lo que significa que una historia de usuario esté “hecha”. Es decir, buscamos cumplir uno de los aspectos más importantes de la historia de usuario: la confirmación&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La manera más efectiva de &lt;strong&gt;añadir detalles&lt;/strong&gt; justo antes de empezar a desarrollarla es utilizando &lt;strong&gt;criterios de aceptación&lt;/strong&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; y &lt;strong&gt;ejemplos&lt;/strong&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; que aclaren el alcance, reduzcan la ambigüedad y ayuden a entender los escenarios&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En el siguiente diagrama mostramos este proceso de detallar una historia mediante &lt;strong&gt;criterios de aceptación&lt;/strong&gt; y &lt;strong&gt;ejemplos&lt;/strong&gt;, y las diferentes preguntas qué nos podrían ayudar a saber si hace falta detallarla más.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/flow-before-develop-feature-add-more-detail.png&quot; alt=&quot;Preguntas clave al añadir más detalle&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Preguntas clave al añadir más detalle&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;paso-1&quot;&gt;Paso 1.&lt;/h3&gt;

&lt;p&gt;Tenemos que examinar cada criterio de aceptación que ya tiene la historia de usuario preguntándonos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Es este criterio de aceptación claro y contiene suficientes ejemplos?&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si un criterio de aceptación no está bien definido o presenta ambigüedades, lo cambiaremos y le añadiremos ejemplos que ayuden a su comprensión.&lt;/p&gt;

&lt;p&gt;Es posible que, tras aclarar estos criterios de aceptación ahora abarquen más de lo esperado.
En ese caso, conviene reevaluar si existe una manera de dividir la historia en incrementos de valor más pequeños.&lt;/p&gt;

&lt;p&gt;Además, por cada uno de los ejemplos de cada criterio de aceptación, podríamos explorar si existen otros escenarios. Para explorar otros escenarios creemos que resulta especialmente útil aplicar los &lt;strong&gt;patrones conversacionales&lt;/strong&gt; que propone &lt;a href=&quot;https://bsky.app/profile/lunivore.bsky.social&quot;&gt;Liz Keogh&lt;/a&gt; en &lt;a href=&quot;https://lizkeogh.com/2011/09/22/conversational-patterns-in-bdd/&quot;&gt;Conversational patterns in BDD&lt;/a&gt;&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Los patrones conversacionales cuestionan el contexto (GIVEN) y el resultado (THEN) de escenarios expresados siguiendo el patrón &lt;a href=&quot;https://martinfowler.com/bliki/GivenWhenThen.html&quot;&gt;Given-When-Then&lt;/a&gt;, de la siguiente manera:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Para cuestionarnos el contexto (GIVEN) nos hacemos preguntas del tipo &lt;strong&gt;¿Existe algún otro GIVEN que, para el mismo WHEN, nos dé un THEN diferente?&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Cuando estamos cuestionando el resultado (THEN) nos hacemos preguntas del tipo &lt;strong&gt;¿Hay algún otro THEN importante dado este contexto GIVEN y WHEN?&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;paso-2&quot;&gt;Paso 2.&lt;/h3&gt;

&lt;p&gt;Una vez hemos aclarado los criterios de aceptación existentes, tenemos que preguntarnos si hacen falta más criterios de aceptación para acabar de aclarar la historia de usuario.&lt;/p&gt;

&lt;p&gt;Para cada nuevo criterio de aceptación que añadamos tenemos que volver aplicar el paso 1.&lt;/p&gt;

&lt;h2 id=&quot;explorar-ejemplos-posibles-particiones&quot;&gt;Explorar ejemplos ¿Posibles particiones?.&lt;/h2&gt;
&lt;p&gt;Al explorar nuevos ejemplos que no habían sido explorados aún o detallar mejor otros, es posible que la historia crezca demasiado. Por tanto, aquí es otro momento en el que conviene volver a reflexionar si existe alguna división que nos pueda ayudar a conseguir entregar antes, reducir riesgo y obtener feedback antes&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;Añadir más detalle a una historia de usuario no consiste en documentar todo de una vez, sino en aclarar progresivamente su alcance hasta lograr un entendimiento compartido de qué significa que la historia de usuario esté “hecha”. Los &lt;strong&gt;criterios de aceptación&lt;/strong&gt; y los &lt;strong&gt;ejemplos&lt;/strong&gt; son las herramientas clave para reducir ambigüedades, alinear al equipo y facilitar tanto la estimación como la validación.&lt;/p&gt;

&lt;p&gt;Durante este proceso es habitual descubrir huecos, nuevos escenarios o incluso la necesidad de dividir la historia para mantenerla manejable y orientada a entregar valor cuanto antes. Por eso, detallar y evaluar el tamaño de la historia deben verse como actividades iterativas y complementarias.&lt;/p&gt;

&lt;p&gt;Aplicar preguntas sistemáticas ayudan a explorar contextos y resultados alternativos, disminuyendo el riesgo de que haya interpretaciones distintas dentro del equipo.&lt;/p&gt;

&lt;p&gt;En definitiva, añadir detalle de forma intencional e incremental mejora la calidad de las historias, reduce incertidumbre y favorece un desarrollo más fluido y predecible, que permitirá entregar valor antes y con menos &lt;em&gt;waste&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Nos gustaría agradecer a &lt;a href=&quot;https://www.pexels.com/@edward-jenner/&quot;&gt;Edward Jenner&lt;/a&gt; la foto.&lt;/p&gt;

&lt;h2 id=&quot;serie-historias-de-usuario&quot;&gt;Serie Historias de Usuario.&lt;/h2&gt;
&lt;p&gt;Este post es parte de una serie sobre Historias de usuario:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/10/flujo-refinar-hu-en-tc&quot;&gt;Nuestro flujo de decisión para refinar Historias de Usuario poco antes de empezar a desarrollarla&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Detallando historias de usuario para acotarlas y reducir su ambigüedad.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;Essential XP: Card, Conversation, Confirmation&lt;/a&gt;, &lt;a href=&quot;https://mastodon.social/@ronjeffries&quot;&gt;Ron Jeffries&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/67834.Extreme_Programming_Installed&quot;&gt;Extreme Programming Installed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2020/05/spidr&quot;&gt;SPIDR, criterios para dividir historias de usuario&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2020/05/spidr&quot;&gt;Twenty Ways to Split Stories&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lizkeogh.com/2011/09/22/conversational-patterns-in-bdd/&quot;&gt;Conversational patterns in BDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/liz-keogh-6240071/&quot;&gt;Liz Keogh&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt;[1] Como ya comentamos en nuestro post &lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt;[2] Hay múltiples heurísticas de particionado. En este post hablamos de &lt;a href=&quot;https://codesai.com/posts/2020/05/spidr&quot;&gt;SPIDR&lt;/a&gt; que puede ser un buen punto de partida. En el curso de &lt;a href=&quot;https://codesai.com/cursos/user-stories/&quot;&gt;Historias de Usuario&lt;/a&gt; nos basamos en el trabajo de &lt;a href=&quot;https://xp123.com/twenty-ways-to-split-stories/&quot;&gt;William Wake&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] La confirmación es uno de los aspectos esenciales enunciados por &lt;a href=&quot;https://mastodon.social/@ronjeffries&quot;&gt;Ron Jeffries&lt;/a&gt; en su &lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;artículo de 2001, Card, Conversation, Confirmation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Algunos autores usan el concepto de condiciones de satisfacción o reglas para hablar de los criterios de aceptación por diferentes motivos. &lt;a href=&quot;https://www.linkedin.com/in/mikewcohn/&quot;&gt;Mike Cohn&lt;/a&gt; prefiere utilizar &lt;a href=&quot;https://www.mountaingoatsoftware.com/blog/clarifying-the-relationship-between-definition-of-done-and-conditions-of-sa&quot;&gt;condiciones de satisfacción&lt;/a&gt; y en &lt;a href=&quot;https://cucumber.io/blog/bdd/example-mapping-introduction/&quot;&gt;Example Mapping&lt;/a&gt; se utiliza el concepto de &lt;strong&gt;Rules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt;[5] Tener ejemplos en la historia de usuario nos ayuda muchísimo a tener un TDD fluido, ya que parte importante del trabajo al hacer TDD es obtener ejemplos reales. Incluso si hacemos los tests a posteriori, también reducimos el coste de hacerlos ya que podemos usar o partir de los ejemplos que la historia contiene.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] Nos gustaría señalar que hay escenarios donde resolver las dudas producidas por la falta de detalle tiene un coste diferente dependiendo de cómo esté organizado el equipo. Por ejemplo, en un equipo que hace &lt;a href=&quot;https://en.wikipedia.org/wiki/Team_programming#Mob_programming&quot;&gt;Mob programming&lt;/a&gt; resolver estas dudas tiene un coste muchísimo más bajo que en un equipo al que, por problemas de disponibilidad, le cueste uno o dos días obtener una respuesta.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Otra técnica interesante para explorar escenarios es aplicar &lt;strong&gt;Decision Table Testing&lt;/strong&gt; (DBT) a escenarios o ejemplos existentes. Hay un ejemplo detallado de cómo aplicar tablas de decisión para explorar escenarios de BDD en la sección &lt;em&gt;11.3.1.1 Behavior-Driven Development&lt;/em&gt; del libro &lt;a href=&quot;https://www.softwaretestcraft.com/home&quot;&gt;Software Testing A Craftsman’s Approach
5th Edition&lt;/a&gt; de &lt;a href=&quot;https://www.softwaretestcraft.com/authors&quot;&gt;Paul C. Jorgensen &amp;amp; Byron DeVries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Hay varias heurísticas interesantes que nos pueden indicar posibles particiones. En este artículo hablamos sobre &lt;a href=&quot;https://codesai.com/posts/2020/05/spidr&quot;&gt;SPIDR&lt;/a&gt;, que puede ser un buen punto de partida. En el curso de &lt;a href=&quot;https://codesai.com/cursos/user-stories/&quot;&gt;Historias de Usuario&lt;/a&gt; nos basamos en el trabajo de &lt;a href=&quot;https://xp123.com/twenty-ways-to-split-stories/&quot;&gt;Bill Wake&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2026-03-27T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/03/detallando-historias</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/03/detallando-historias</guid>
        </item>
      
    
      
        <item>
          <title>Metadocumenting to Improve Our Interactions with Coding Agents: Capturing Reasoning, Summaries, and Prompt Feedback</title>
          <description>&lt;p&gt;Lately I’ve been experimenting with a small addition to my project setup when practising with coding agents.&lt;/p&gt;

&lt;p&gt;I add a &lt;strong&gt;meta documentation&lt;/strong&gt; section at the end of my project instructions (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copilot-instructions.md&lt;/code&gt;) that asks the agent to generate three small markdown files after every change to the code: one documenting the agent’s reasoning, another one giving me feedback on my prompt and the last one including an extended summary of the changes.&lt;/p&gt;

&lt;h3 id=&quot;1-the-reasoning-file&quot;&gt;1. The reasoning file.&lt;/h3&gt;

&lt;p&gt;This file documents the step-by-step decisions and alternatives considered by the agent. It helps me see how the agent approached its solution, including trade-offs and paths not taken. I can learn about options I hadn’t considered, or see how distinct trade-offs were evaluated when making a decision. It’s reassuring for me, somehow, when I find that the agent makes the right choice for the right reasons.&lt;/p&gt;

&lt;h3 id=&quot;2-the-prompt-feedback-file&quot;&gt;2. The prompt feedback file.&lt;/h3&gt;

&lt;p&gt;In this file the agent critiques my original request and suggests how I can improve it. It highlights where I was vague or could have structured things better. It also highlights the information and structure in my prompts that were most useful to the agent. Hopefully, this feedback will help me to reflect and gradually improve how I communicate with the agent.&lt;/p&gt;

&lt;h3 id=&quot;3-the-extended-summary-file&quot;&gt;3. The extended summary file.&lt;/h3&gt;

&lt;p&gt;This file explains what changed, why it matters, and what to review. Its content is similar to what the agents I’ve worked with give me by default, but enriched with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The “Why” behind the changes&lt;/strong&gt;. This helps me to connect each change made to its intent. Reading the “Why” the agent is able to deduce helps me see how aligned the agent and I are, and discover new points of view.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The consequences of each change and follow-up actions the agent thinks I should be aware of&lt;/strong&gt;. This has already helped me identify some potential pitfalls and mistakes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;A list of key aspects to verify during code review, and advice on how to ensure that they are verified during the review&lt;/strong&gt;. Personally, since I’ve been mostly trying big, involved refactorings so far, what I’m striving for is for the agent to tell me that there’s nothing to review because all aspects were covered by tests. When that is not the case, it means I’ve discovered something to improve in my process.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal with these metadocuments is to somehow get some visibility into the decision-making process of the agent in order to create a learning loop that will help me build my intuition.&lt;/p&gt;

&lt;p&gt;I’ve iterated this &lt;strong&gt;meta documentation&lt;/strong&gt; section several times with the feedback I’ve received from different agents. This is the one I’m currently using:
&lt;script src=&quot;https://gist.github.com/trikitrok/0f221d306ab4f47d866914a00ae55e75.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;I asked &lt;a href=&quot;https://github.com/copilot&quot;&gt;Copilot&lt;/a&gt; (with &lt;a href=&quot;https://www.anthropic.com/claude/sonnet&quot;&gt;Claude Sonnet 4.6&lt;/a&gt;) what he thought was the intention of the &lt;strong&gt;meta documentation&lt;/strong&gt; section, and it replied the following:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1333e245ee8f2859dc81e5c82b79ceeb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I’ve found this &lt;strong&gt;meta documentation&lt;/strong&gt; especially helpful in the learning context I’m in. Instead of just reviewing the result the agent generates, I get a bit more insight into how the agent put it together, and how I might improve my next interaction with the agent.&lt;/p&gt;

&lt;p&gt;In a big production context, I likely wouldn’t add the &lt;strong&gt;meta documentation&lt;/strong&gt; section to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AGENTS.md&lt;/code&gt;. Instead, I’d rather have a command or a stored prompt to only add these documents in sessions in which I consider it worths the trouble.&lt;/p&gt;

&lt;p&gt;It’s a small thing, but it’s been for me a useful way to reflect a bit more on both the code and how I’m working with the agent. Maybe it might be useful to you as well.&lt;/p&gt;

&lt;p&gt;In future posts about my experiences coding with agents I plan to include things I’ve learned using this meta documentation (now you’ll know where those learnigs come from).&lt;/p&gt;

&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h3&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/mjtordesillas/&quot;&gt;Manuel Tordesillas&lt;/a&gt; for encouraging me to write this post, and &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/fernandoaparicio/&quot;&gt;Fernando Aparicio&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@joshuaworoniecki/&quot;&gt;Joshua Woroniecki&lt;/a&gt; for the photo.&lt;/p&gt;

</description>
          <pubDate>2026-03-25T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/03/metadocumenting-ai-agents-work</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/03/metadocumenting-ai-agents-work</guid>
        </item>
      
    
      
        <item>
          <title>Refactoring with AI: Lessons in Introducing a Decorator Pattern</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/separating-responsibilities-with-decorator&quot;&gt;In a previous post&lt;/a&gt; we explained a refactoring we did to make code and tests more maintainable by introducing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Decorator_pattern&quot;&gt;decorator&lt;/a&gt; to separate responsibilities.&lt;/p&gt;

&lt;p&gt;We refactored the original code and its tests using the &lt;a href=&quot;https://www.jetbrains.com/ai-assistant/&quot;&gt;AI assistant&lt;/a&gt; in &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post shows how we guided the AI assistant through this refactoring, the problems we faced and our learnings.&lt;/p&gt;

&lt;h2 id=&quot;introducing-the-decorator&quot;&gt;Introducing the decorator.&lt;/h2&gt;

&lt;p&gt;This is the initial code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/6a2edb78c7bb683778527e2688c074c2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We prompted the AI assistant with:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;create a decorator of CompanyApi called WithErrorHandlingCompanyApi that handles
all the possible error cases that AcmeCompanyApi is currently handling&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This prompt made the AI assistant create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt; decorator and simplify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; class by removing all the error handling:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/608a9572e132d795a8896f59a2360572.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ca9ba76fe509bb81641ecd7cda2b290b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;It did it much better than we expected taking into account we just used a one-shot prompt and no rules file: the tool correctly created the decorator and removed all the error handling logic from the decorated class. We think that using design patterns vocabulary in the prompt might have helped.&lt;/p&gt;

&lt;p&gt;However, it forgot to update the factory function that was creating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; which made the tests fail:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7ea0a1b483e417f534e536189ae1cbd7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;So, we updated it manually to make all tests pass again:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/140242dc52509f24fc0bf86ffd76c5c4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We could have reduced the probability of the AI forgetting to update the factory function if we had given it a better context&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aside from this mistake, the AI-assistant nearly did the refactoring quite well, and, we think, it took less time than it had taken us doing it on our own with the help of &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later we discovered that the AI assistant had slipped in a problem that, while not breaking the behavior, did weaken the type checking. Maybe you’ve already noticed the problem, we didn’t in our first review.&lt;/p&gt;

&lt;p&gt;The AI-assistant had changed the signature of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open&lt;/code&gt; function in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; interface from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async open(claim: Claim): Promise&amp;lt;OpeningResult&amp;gt;&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async open(claim: Claim): Promise&amp;lt;any&amp;gt;&lt;/code&gt;, relaxing the type. This was an unintended change, and not that easy to detect. We only noticed the problem after a while when we were reviewing the result of another AI-assisted transformation.&lt;/p&gt;

&lt;p&gt;In retrospect, we could have automatically detected this problem with a linter. For instance, using &lt;a href=&quot;https://typescript-eslint.io/&quot;&gt;typescript-eslint&lt;/a&gt; with the &lt;a href=&quot;https://typescript-eslint.io/rules/no-explicit-any&quot;&gt;no-explicit-any rule&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. We think this kind of guardrail would become even more crucial if we were working with coding agents.&lt;/p&gt;

&lt;h2 id=&quot;simplifying-the-tests&quot;&gt;Simplifying the tests.&lt;/h2&gt;

&lt;p&gt;These were the original tests we had for the error handling in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; (we had separated in different files the tests for the happy past and the error handling):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/37f919245981b4b3c72b33b6bd572443.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;They were still simulating the behaviour of the interfaces &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForGettingCauses&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForOpeningClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AuthTokenRetriever&lt;/code&gt; with test doubles.&lt;/p&gt;

&lt;p&gt;These tests did a great job protecting the behaviour while introducing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt; decorator (they had catched an error introduced by the AI changes, remember), but, once the decorator was there, we used the AI assistant to simplify the tests and reduce their coupling to the production code.&lt;/p&gt;

&lt;p&gt;We used the following prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;change the tests so that they test the WithHandlingErrorsCompanyApi.
The test should mock only the CompanyApi interface&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI assistant modified the tests producing the following code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d8e71681a7060eb76136aea47c8b8de9.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;It nearly got it right, however this code did not type check because the usage of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockRejectedValue&lt;/code&gt; was producing the following error:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TS2345: Argument of type CannotRetrieveTokenError is not assignable to parameter of type never&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We asked the AI assistant how to fix it but it started to hallucinate badly…&lt;/p&gt;

&lt;p&gt;After some research on our own, we found that using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockImplementation&lt;/code&gt; worked, so we prompted the AI to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockImplementation&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockRejectedValue&lt;/code&gt;, and that fixed the tests:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockImplementation&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockRejectedValue&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We still need to learn to recognize sooner when AI is confidently leading us down  a wrong path, and we’d be better off retaking control.&lt;/p&gt;

&lt;p&gt;A pleasant surprise was that we learned that it’s possible to type the functions you are mocking with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jest.fn()&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9555dd25f90012a8b218ecfb257fa0d1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is an example of how we can use AI to learn alternative ways to do something.&lt;/p&gt;

&lt;p&gt;Once it worked, we used the IDE to remove the unused factory function at the end of the file.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ae17f3105e2d74d00a3e8e3ebe63fc34.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then we told the AI assistant to add a test that was missing using the following prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;add a test case for when it fails with an unknown error&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It didn’t need more context because we used the inline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Generate code with AI&lt;/code&gt; option of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Generate command&lt;/code&gt; in &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;. This was the generated code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5306dab6dcc3e7031001587f5563b6c3.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;As we explored in our &lt;a href=&quot;https://codesai.com/posts/2026/02/separating-responsibilities-with-decorator&quot;&gt;previous post&lt;/a&gt;, the goal of this refactoring was to move from a coupled implementation to a clean separation of concerns. The following table summarizes the structural shift we were aiming for:&lt;/p&gt;

&lt;table class=&quot;zebraTable&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Original code&lt;/th&gt;
      &lt;th&gt;Refactored (Decorator Pattern)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Business Logic&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Mixed with error handling&lt;/td&gt;
      &lt;td&gt;Isolated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; (decoratee)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Mixed with business logic&lt;/td&gt;
      &lt;td&gt;Encapsulated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt; (decorator)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Test-to-production-code coupling&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;3 interfaces (3 test doubles)&lt;/td&gt;
      &lt;td&gt;1 interface (1 test double)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;figcaption&gt;&lt;strong&gt;Reduction in complexity.&lt;/strong&gt;&lt;/figcaption&gt;

&lt;h2 id=&quot;simplifying-the-design&quot;&gt;Simplifying the design.&lt;/h2&gt;

&lt;p&gt;Then we created a factory class to compose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; and the decorator that handled its errors with the following prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApiFactory&lt;/code&gt; class with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create&lt;/code&gt; static method that composes
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; and the handling errors decorator.
Do not use it anywhere yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;which produced the following class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/21323d2bf7be93237d2767c521c5e48b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Next we introduced the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyConfig&lt;/code&gt; as fourth parameter of the constructor of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; using the IDE and then prompted the AI with:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;initialize the fields creating instances of the 3 interfaces in the constructor and change the signature of the constructor so that it receives only the configuration&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We could have omitted the last step, changing the constructor interface to remove the unused parameters, using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Change Signature&lt;/code&gt; automatic refactoring instead.&lt;/p&gt;

&lt;p&gt;This would have been a much safer option because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Change Signature&lt;/code&gt; is a deterministic transformation unlike using AI. However, we wanted to explore if the AI assistant could manage this transformation well, and so it did:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/96fc585d5083fcbb0439d5b258c37599.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Finally, we asked &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt; (&lt;a href=&quot;https://www.jetbrains.com/&quot;&gt;JetBrains&lt;/a&gt;’ agentic assistant that can handle multi-file tasks and verify its own work) to do the following:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;use the implementations of the 3 interfaces to type the fields in the AcmeCompanyApi and  then remove the interfaces &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForGettingCauses&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForOpeningClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AuthTokenRetriever&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;in order to &lt;a href=&quot;https://emmanuelvalverderamos.substack.com/p/materialization-turning-a-false-peer&quot;&gt;materialise&lt;/a&gt; the peers demoting them to be internals. It produced the following code that worked fine:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a6f9065fc570a41d5a7092f0954ab7ba.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We only had to manually remove the default value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt; parameter in the constructor to finish the job.typescript-eslint&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;The post describes how we used an AI assistant in &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; to refactor a codebase by introducing a decorator that separates error-handling responsibilities from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; class. With a simple prompt, the AI successfully created the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt; decorator and simplified the original class. However, it failed to update the factory that instantiated the API, causing tests to break, which we fixed manually. Later we also discovered an unintended weakening of type safety: the AI had changed a return type to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;any&amp;gt;&lt;/code&gt;. A linter such as &lt;a href=&quot;https://typescript-eslint.io/&quot;&gt;typescript-eslint&lt;/a&gt; could have caught this. This emphasizes the importance of guardrails.&lt;/p&gt;

&lt;p&gt;We then used the AI assistant to simplify existing tests. Originally, the tests relied on multiple test doubles, but we prompted the AI to rewrite them so only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; interface was simulated. The AI’s first attempt produced type errors when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockRejectedValue&lt;/code&gt;, and its suggested fix was incorrect. After our own investigation, we instructed the AI to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mockImplementation&lt;/code&gt;, which resolved the issue. This reinforced the need to recognize when AI guidance is unreliable. A pleasant surprise was that we also learned a new technique: typing functions mocked  with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jest.fn()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After cleaning up unused code, we asked the AI to add a missing test case for unknown errors, which it generated correctly. We then moved on to simplify the overall design by prompting the AI to create an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApiFactory&lt;/code&gt; to compose the concrete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; with its decorator. We further refactored the constructor to accept only configuration and to instantiate dependencies internally. Although we could have done this simple deterministic refactoring safer with the IDE, we wanted to explore if the AI could handle this transformation successfully. It did.&lt;/p&gt;

&lt;p&gt;Finally, we used &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt; to replace several interfaces with concrete implementations, to effectively internalise those collaborators. The generated code worked with only a small manual adjustment needed. Overall, we conclude that the AI assistant significantly sped up the refactoring but also introduced subtle issues, reinforcing the need for careful review, tooling guardrails, and knowing when to take back manual control.&lt;/p&gt;

&lt;h2 id=&quot;learnings&quot;&gt;Learnings.&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;AI sped up a refactoring that would have taken several steps with the IDE&lt;/strong&gt;: The AI assistant significantly accelerated the process of introducing the decorator. We used it also to create a factory class, although in this latter case doing it with the IDE would have taken  less or as long. We think that using a pattern as a refactoring target helped guide the AI assistant&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;AI lacks global awareness&lt;/strong&gt;: While the AI successfully introduced the decorator, it failed to update the factory that instantiated it, causing broken tests. We could have reduced the probability of this happening by using a better prompt that gave the AI more context.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Subtle degradations are difficult to detect and we’ll need as much help as we can get&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;&lt;/strong&gt;: The AI introduced an unintended subtle change that was difficult to notice: it weakened type safety by changing some return types to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;any&amp;gt;&lt;/code&gt;. It’s difficult for humans to review and detect errors in code that works and is “nearly correct”. We think that we can improve our chances by using automatic, deterministic tools to support us. In this case, a &lt;strong&gt;linter&lt;/strong&gt; triggered by a &lt;strong&gt;git hook&lt;/strong&gt; could have detected and even fixed the type weakening.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Importance of external guardrails&lt;/strong&gt;: Automatic testing, linters and other tools are going to be more and more necessary to prevent behavioural errors and other problems such as technical debt that AI may introduce into the codebase&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Limits of AI troubleshooting&lt;/strong&gt;: When the AI’s first attempt to simplify the tests produced type errors, it started hallucinating incorrect fixes. In the end, we had to investigate on our own and fix the problems manually. It’s important to learn to recognize earlier. We need to learn to recognize sooner when AI is confidently leading us down  a wrong path, and we’d be better off retaking control.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;AI as a source of new techniques&lt;/strong&gt;: We had the pleasant surprise of learning from the AI a technique for typing functions mocked with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jest.fn()&lt;/code&gt; that we didn’t know.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Knowing which tool to apply&lt;/strong&gt;: Even though we used AI for most of the refactorings to explore how it managed, we think that some of them could have been made more safely and faster with deterministic, automatic IDE refactorings, or other deterministic tools like &lt;a href=&quot;https://docs.openrewrite.org/&quot;&gt;OpenRewrite&lt;/a&gt;. Knowing and practising with other tools aside from AI gives you more options.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’ll go on writing about what we learn as we go on using AI coding tools.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/fernandoaparicio/&quot;&gt;Fernando Aparicio&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;
for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@maxwell-pels-1372108218/&quot;&gt;Maxwell Pels&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://itrevolution.com/product/vibe-coding-book/&quot;&gt;Vibe Coding&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/realgenekim/&quot;&gt;Gene Kim&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Steve_Yegge&quot;&gt;Steve Yegge&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/separating-responsibilities-with-decorato&quot;&gt;Composing responsibilities to reduce coupling and improve tests’ maintainability&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://emmanuelvalverderamos.substack.com/p/materialization-turning-a-false-peer&quot;&gt;Materialization: turning a false peer into an internal&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/&quot;&gt;Augmented Coding Patterns&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/lada-kesseler/&quot;&gt;Lada Kesseler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html&quot;&gt;Harness Engineering&lt;/a&gt;, &lt;a href=&quot;https://birgitta.info/&quot;&gt;Birgitta Böckeler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Chatting with &lt;a href=&quot;https://gemini.google.com/app&quot;&gt;Gemini&lt;/a&gt; about the problems and ways to improve the prompt to give better context to the AI assistant, it suggested me to use an improved prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Refactor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; by creating a decorator named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt; to handle all its current error-handling responsibilities. After creating the decorator, identify every location in the codebase where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; is instantiated—specifically checking factories or dependency injection modules—and update them to compose the new decorator with the concrete implementation. Ensure that the return types remain strictly typed and do not revert to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and explained to me why this prompt is better than the one I used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Defines the “Blast Radius”:&lt;/strong&gt; By explicitly mentioning “every location where it is instantiated,” you force the AI to look beyond the single file.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Targets the Weak Point:&lt;/strong&gt; Specifically calling out “factories” reminds the AI of the specific architectural layer it missed last time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sets Type Guardrails:&lt;/strong&gt; The instruction regarding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;any&lt;/code&gt; prevents the silent degradation of type safety you encountered previously.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Enforces Composition:&lt;/strong&gt; It provides a clear architectural goal (composition) rather than just a code transformation.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We went on discussing the &lt;strong&gt;type guardrails&lt;/strong&gt;, because, to avoid using up context space, we prefer preventing the type degradation in a deterministic way using a linter triggered by a hook.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] &lt;a href=&quot;https://gemini.google.com/app&quot;&gt;Gemini&lt;/a&gt; also suggested us how to set up &lt;a href=&quot;https://typescript-eslint.io/&quot;&gt;typescript-eslint&lt;/a&gt; and a &lt;strong&gt;git hook&lt;/strong&gt; using &lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;husky&lt;/a&gt; and &lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;lint-staged&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We could also do this with something similar to Claude’s &lt;a href=&quot;https://code.claude.com/docs/en/hooks-guide&quot;&gt;hooks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;https://www.linkedin.com/in/lada-kesseler/&quot;&gt;Lada Kesseler&lt;/a&gt;’s &lt;a href=&quot;https://lexler.github.io/augmented-coding-patterns/pattern-catalog/&quot;&gt;Hook pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] We think that using the vocabulary of design patterns may improve outcomes because they encode roles, boundaries, and expectations in a compact form. This is a form of &lt;strong&gt;semantic compression&lt;/strong&gt;: by using the single word “Decorator,” you replace what would otherwise be a detailed technical specification (interface adherence, delegation logic, and constructor injection). For a LLM pattern names likely function not only as semantic guides but also as statistical anchors that steer code generation toward familiar code shapes. This may be helpful to reduce ambiguity and structural drift, but there’s also the risk of prematurely converging on canonical solutions that are not actually the best fit for the problem at hand. We think we still need to study and know when to apply a given pattern and their forces, trade-offs and consequences.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4]  See this interesting talk by &lt;a href=&quot;https://damianbrady.com.au/about/&quot;&gt;Damian Brady&lt;/a&gt;: &lt;a href=&quot;https://www.youtube.com/watch?v=DZpR0GojoWQ&quot;&gt;The dangers of probably-working software&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Have a look at &lt;a href=&quot;https://birgitta.info/&quot;&gt;Birgitta Böckeler&lt;/a&gt;’s great post &lt;a href=&quot;https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html&quot;&gt;Harness Engineering&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After discussing for a while with ChatGpt and Gemini (I do that sometimes now…) about a more specific: topic “harnessing AI assisted refactorings”, I got this nice visual summary of the discussion from Gemini:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/navigating_ai_assisted_refactoring.png&quot; alt=&quot;Navigating AI assisted refactoring.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;Navigating AI assisted refactoring&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There are many other missing things that can help like, for instance, dividing the transformations in small steps to reduce risk and facilitate reviews, etc.&lt;/p&gt;

&lt;p&gt;I wonder, if the old concept of &lt;a href=&quot;https://web.archive.org/web/20090912154715/http://www.refactoring.be/thumbnails/thumbnails.html&quot;&gt;Refactoring Thumbnails&lt;/a&gt; 
might also help us guide AI-assisted refactorings, (I learned about &lt;a href=&quot;https://web.archive.org/web/20090912154715/http://www.refactoring.be/thumbnails/thumbnails.html&quot;&gt;Refactoring Thumbnails&lt;/a&gt; in the book &lt;a href=&quot;https://www.wiley.com/en-us/Refactoring+in+Large+Software+Projects%3A+Performing+Complex+Restructurings+Successfully-p-9780470858936&quot;&gt;Refactoring in Large Software Projects&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/stefanroock&quot;&gt;Stefan Roock&lt;/a&gt; and &lt;a href=&quot;https://github.com/martinlippert&quot;&gt;Martin Lippert&lt;/a&gt;). For instance, this is the thumbnail for &lt;a href=&quot;https://web.archive.org/web/20090914082645/http://www.refactoring.be/thumbnails/ec-proxy.html&quot;&gt;Evolving to the Proxy / Decorator Pattern&lt;/a&gt;:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/evolving-to-proxy-decorator.png&quot; alt=&quot;Refactoring Thumbnail for Evolving to the Proxy / Decorator Pattern.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;Refactoring Thumbnail for &lt;strong&gt;Evolving to the Proxy / Decorator Pattern&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

</description>
          <pubDate>2026-03-05T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/03/ai-refactor_to_decorator</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/03/ai-refactor_to_decorator</guid>
        </item>
      
    
      
        <item>
          <title>Relevant Mutants in a Flash</title>
          <description>&lt;div class=&quot;flashcard&quot;&gt;
&lt;h3&gt;Relevant Mutants.&lt;/h3&gt;

&lt;hr class=&quot;flashcard-line&quot; /&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Not all surviving mutants indicate weaknesses in tests.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not relevant surviving mutants&lt;/strong&gt; (don’t signal any test weakness):
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ignore&lt;/strong&gt; these ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_code&quot;&gt;dead code&lt;/a&gt; (unreachable code)&lt;/li&gt;
&lt;li&gt;In &lt;a href=&quot;https://martinfowler.com/bliki/LegacySeam.html&quot;&gt;legacy seams&lt;/a&gt; (intentionally excluded from test execution).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code not used because of&lt;/strong&gt; &lt;a href=&quot;https://martinfowler.com/bliki/LegacySeam.html&quot;&gt;legacy seams&lt;/a&gt; (also intentional).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mutants in superfluous code&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They survive because the &lt;strong&gt;mutation did not change&lt;/strong&gt; any &lt;strong&gt;behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Still useful&lt;/strong&gt; 💰: signal a possible &lt;strong&gt;simplification&lt;/strong&gt; (refactoring opportunity).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relevant surviving mutants&lt;/strong&gt; 💰: reveal genuine gaps in the test suite
&lt;ul&gt;
&lt;li&gt;e.g. missing boundaries, too lenient assertions, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&quot;https://codesai.com/posts/2024/07/relevant-mutants&quot;&gt;Relevant Mutants&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</description>
          <pubDate>2026-02-27T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/02/relevant_mutants_in_a_flash</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/02/relevant_mutants_in_a_flash</guid>
        </item>
      
    
      
        <item>
          <title>Usando Combinaciones de ApprovalsJs en WebStorm</title>
          <description>&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;
&lt;p&gt;En un &lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;post anterior&lt;/a&gt;, explicamos como integrar &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; con &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; para facilitar la aplicación de la técnica &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master + Sampling&lt;/a&gt; que puede ser muy útil cuando trabajamos con código legacy&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; nos ayuda con algunos de los pasos más complicados y/o engorrosos de la técnica &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master + Sampling&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;una-estrategia-para-el-sampling&quot;&gt;Una estrategia para el sampling.&lt;/h2&gt;
&lt;p&gt;Una de las partes más tediosas, pero necesaria para poder aplicar la técnica &lt;strong&gt;Golden Master&lt;/strong&gt; es obtener el input y el output necesarios para generar los datos de nuestro golden master inicial, esta obtención de datos es lo que se conoce como &lt;strong&gt;sampling&lt;/strong&gt; (muestreo).&lt;/p&gt;

&lt;p&gt;Existen diferentes estrategias para hacer el muestreo. Algunas de ellas son:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Hacer combinatoria de inputs relevantes para el flujo de la aplicación y grabar el output correspondiente. Esta estrategia se puede hacer incrementalmente o con utilidades facilitadas por librerías.&lt;/li&gt;
  &lt;li&gt;Generar input de forma aleatoria y grabar el output correspondiente.&lt;/li&gt;
  &lt;li&gt;Grabar el input y output en una ejecución real del software para luego usarlo en los tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La elección de una u otra estrategia dependerá de nuestro contexto, pero lo ideal es elegir una estrategia que nos permita generar el golden master con el menor coste posible.&lt;/p&gt;

&lt;p&gt;Si tras evaluar nuestras opciones está la posibilidad de hacer combinatoria de inputs (estrategia 1), la librería &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; puede facilitar bastante este trabajo.&lt;/p&gt;

&lt;h2 id=&quot;generando-combinaciones-de-inputs-con-approvals&quot;&gt;Generando combinaciones de inputs con Approvals.&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; proporciona la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; que genera todas las combinaciones posibles de los valores de inputs que le indiquemos.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; también se encarga de grabar el output aprobado.&lt;/p&gt;

&lt;p&gt;La aprobación del output es responsabilidad del desarrollador, aunque, como ya vimos en posts anteriores, &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; proporciona herramientas que la facilitan.&lt;/p&gt;

&lt;p&gt;La firma de la función recibe como primer parámetro la función que ejecutará al sistema que estamos testeando y devolverá el output que esperamos verificar. Los siguientes parámetros de entradas son opcionales, y cada uno de ellos es un array de valores correspondiente a cada parámetro de la función que ejecuta al sistema que estamos testeando.&lt;/p&gt;

&lt;p&gt;Veamos un ejemplo de uso:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/b1c77babe2f6ab916fcdcad711d7f9a6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;El test que se muestra en el ejemplo generará como input para la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateStore&lt;/code&gt; el producto cartesiano de los conjuntos {‘Regular’}, {0, 1, 5} y {20, 50, 49, 1}. Eso quiere decir que, cuando aceptamos el output que produce el test, habremos generado un golden master que consta de 1 x 3 x 4 = 12 ejemplos que son el resultado de combinar los conjuntos de inputs iniciales, es decir habrá un ejemplo cuyo input es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;Regular&apos;, 0, 20&lt;/code&gt;, otro con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;Regular&apos;, 1, 20&lt;/code&gt;, otro con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;Regular&apos;, 5, 20&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;Usar combinaciones con &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; puede ser muy útil en aquellos casos en los que conocemos qué valores de inputs son relevantes para conseguir ejercitar diferentes flujos de ejecución.&lt;/p&gt;

&lt;h2 id=&quot;problemas-al-usar-verifyallcombinations-en-webstorm&quot;&gt;Problemas al usar verifyAllCombinations en WebStorm.&lt;/h2&gt;
&lt;p&gt;En post anteriores, explicamos cómo al utilizar &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; desde &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; nos encontramos con el problema de que no lanzaba la herramienta de diff que se usa en caso de encontrar discrepancias entre el output aprobado (golden master) y el output real que está generando la ejecución de los tests (dicha herramienta se denomina &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;). Dicho problema lo superamos configurando la herramienta para incluir en la lista de &lt;strong&gt;reporters&lt;/strong&gt;, un reporter que creamos para que funcione con la herramienta de diff de &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Este era su código:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/dfdb2032924f80d37c5d93f84c2b3c28.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Pero esta solución no nos sirve en el caso de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/master/docs/how_tos/TestCombinationOfParameters.md&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt;&lt;/a&gt; ya que este método no nos permite configurar qué reporter usar pasando un parámetro, como sí que hacía la función &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS?tab=readme-ov-file#approvalsverifyasjsondirname-testname-data-optionsoverride&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAsJson&lt;/code&gt;&lt;/a&gt;. Así que debemos buscar otra solución.&lt;/p&gt;

&lt;h2 id=&quot;nuestra-solución&quot;&gt;Nuestra solución.&lt;/h2&gt;
&lt;p&gt;La solución que hemos encontrado para poder configurar el reporter consiste en cambiar la configuración por defecto de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; antes de ejecutar la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como la configuración por defecto de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; tiene un ámbito global, cualquier cambio que le hagamos puede influir en la ejecución de otros tests. Para evitarlo, debemos deshacer el cambio después de ejecutar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; dejando la configuración por defecto de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; en su estado anterior.
Con este fin escribimos un wrapper para la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt;. Nuestro wrapper, primero, modifica la configuración de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; para que use el reporter que queremos, después llama a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt;, y por último, deja la configuración como estaba inicialmente.&lt;/p&gt;

&lt;p&gt;Este es el código del wrapper:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/5408e71004433e1ae545482d744bb997.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;La clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt; se quedó como estaba.&lt;/p&gt;

&lt;p&gt;Para utilizar el wrapper solo tenemos que importarlo en nuestros tests en vez de importar la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; de la librería. Con esto ya basta porque el wrapper tiene la misma firma que la función de la librería:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/475d86f17b51df8810db8158b6c3e151.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;En este post abordamos un problema que se nos presentó al usar la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; desde &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; en el contexto de la técnica &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master + Sampling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Resulta que en &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; no se lanza correctamente la herramienta de diff cuando aparecen discrepancias entre el output aprobado y el que generan los tests. Esto sucede porque la interfaz de la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; no permite configurar el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reporter&lt;/code&gt; por parámetro, a diferencia de otras funciones de la librería.&lt;/p&gt;

&lt;p&gt;La solución práctica que planteamos consiste en crear un wrapper alrededor de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt;. Este wrapper cambia la configuración por defecto para forzar que se use el reporter compatible con &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; que presentamos en posts anteriores, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;, ejecuta la verificación y finalmente restaura la configuración original para evitar que se vean afectados otros tests. De este modo, podemos usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAllCombinations&lt;/code&gt; en &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; sin perder la integración con la su propia herramienta de diff.&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias.&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;Integrando ApprovalsJS con WebStorm&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/usando-approvalsjs-y-strykerjs-en-webstorm&quot;&gt;Usando conjuntamente ApprovalsJs y StrykerJS en WebStorm&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Surviving Legacy Code with Golden Master and Sampling&lt;/a&gt; by J.B. Rainsberger.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=n-JSrvW4MVs&quot;&gt;Video de Llewellyn Falco usando Approvals Combination en .Net&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Vemos esta y otras técnicas en profundidad en nuestro curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/master/docs/README.md&quot;&gt;Approvals&lt;/a&gt; define toda una serie de abstracciones fundamentales (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Writer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Namer&lt;/code&gt;..) que permiten extender su comportamiento y adaptarlo en caso de que sea necesario.&lt;/p&gt;
</description>
          <pubDate>2026-02-25T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/02/usando-combinaciones-approvalsjs-en-webstorm</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/02/usando-combinaciones-approvalsjs-en-webstorm</guid>
        </item>
      
    
      
        <item>
          <title>Composing responsibilities to reduce coupling and improve tests&apos; maintainability</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;We’d like to show an example of how composing responsibilities reduced the coupling between tests and production code and enabled simplifications, both in tests and production code, which led to more maintainable tests.&lt;/p&gt;

&lt;h2 id=&quot;the-original-code&quot;&gt;The original code.&lt;/h2&gt;

&lt;p&gt;This is the original code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; class.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7754271af5a71eac74d80c08c5119dfa.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; had the responsibility of opening a claim in Acme insurance company. To do that, it was coordinating interactions with three endpoints that were required to open a claim. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; was also in charge of handling all the possible exceptions that those interactions can throw.&lt;/p&gt;

&lt;p&gt;We had a broad integration test written using &lt;a href=&quot;https://wiremock.org/&quot;&gt;Wiremock&lt;/a&gt; for the happy path of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; that was &lt;a href=&quot;https://en.wikipedia.org/wiki/Service_virtualization&quot;&gt;virtualizing&lt;/a&gt; the three endpoints. We also had focused integration tests for each endpoint also using &lt;a href=&quot;https://wiremock.org/&quot;&gt;Wiremock&lt;/a&gt; to check that all possible errors were mapped to domain exceptions.&lt;/p&gt;

&lt;p&gt;Since test-driving the error handling in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; with broad integration tests felt too cumbersome, we decided to introduce three interfaces (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForGettingCauses&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForOpeningClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AuthTokenRetriever&lt;/code&gt;) to simulate problems in the interactions with the endpoints.
Notice that these interfaces were introduced only to make testing the error handling logic easier and that they had only one implementation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCausesEndpoint&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeClaimOpeningEndpoint&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeAuthTokenRetriever&lt;/code&gt;, respectively).&lt;/p&gt;

&lt;p&gt;These are the initial tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt;’s error handling logic:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/37f919245981b4b3c72b33b6bd572443.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The problem with these tests was that they had a low &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; because they are coupled to&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForGettingCauses&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForOpeningClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AuthTokenRetriever&lt;/code&gt;, 
and any change in those interfaces would force to change the tests of the error handling logic, even in cases in which its behaviour hadn’t changed.&lt;/p&gt;

&lt;p&gt;How can we enhance the structure-insensitivity of tests for error handling logic while simultaneously avoiding having to write cumbersome broad integration tests?&lt;/p&gt;

&lt;h2 id=&quot;the-real-problem-poor-separation-of-concerns&quot;&gt;The real problem: poor separation of concerns.&lt;/h2&gt;

&lt;p&gt;We traced the origin of the problem to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; having too many responsibilities:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Opening a claim.&lt;/li&gt;
  &lt;li&gt;Handling all the possible exceptions that could be raised and mapping them to an adequate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We decided to separate those two responsibilities by introducing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Decorator_pattern&quot;&gt;decorator&lt;/a&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; 
that would be in charge of handling the errors, that we could compose with a new version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt;, only responsible for opening a claim.&lt;/p&gt;

&lt;p&gt;We used AI assistance to introduce this decorator, and it went quite well. We’ll explain the process in a future post. 
This post focuses only on how separating responsibilities reduced coupling between tests and production code, and thus, improved the tests’ maintainability.&lt;/p&gt;

&lt;h2 id=&quot;the-code-after-introducing-the-decorator&quot;&gt;The code after introducing the decorator.&lt;/h2&gt;

&lt;p&gt;This is the resulting code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; class after introducing the decorator:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/08aa74dded7df4fa9c80a0da57fad57f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how there’s no error handling logic left.&lt;/p&gt;

&lt;p&gt;This is the code of the new decorator, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithErrorHandlingCompanyApi&lt;/code&gt;, in which we moved the error handling logic:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8dfc480b9a379c38d2cfcb112350069f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The simplified tests of the error handling logic are now only coupled to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; interface. 
Remember that with the previous design these tests were coupled to three interfaces which had only one implementation each (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForGettingCauses&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForOpeningClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AuthTokenRetriever&lt;/code&gt;).&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/69ff5e9cd657941e441160c41b4cc588.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These tests were also simplified with AI assistance.&lt;/p&gt;

&lt;p&gt;Since the tests were not coupled to these interfaces any more, we &lt;strong&gt;materialised&lt;/strong&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; those three peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt;. 
This is the resulting code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; using internals instead of peers:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d1a7306ac02ad664e5aa0ca08bb03bfd.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This &lt;strong&gt;materialisation&lt;/strong&gt; of the peers was done by AI, as well.&lt;/p&gt;

&lt;p&gt;Finally, we completely removed the usage of the unnecessary interfaces from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/078dc61f8bec5ce9af5be563053cec39.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and deleted the unused interfaces.&lt;/p&gt;

&lt;p&gt;Separating responsibilities led to both production code and tests that were easier to evolve and maintain. 
We achieved these benefits by introducing composition. However, this leads to a new problem: &lt;em&gt;how should we know if the object graph we compose has the desired behaviour?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To avoid this decrease in &lt;a href=&quot;https://www.youtube.com/watch?v=7o5qxxx7SmI&quot;&gt;predictability&lt;/a&gt;, we can complement 
the existing unit tests with one broad integration test that checks the desired composed behaviour is there.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;In this post we have shown how an object with too many responsibilities can lead us to unintentionally increase coupling between tests and production code, 
when we try to make it easier to test-drive. We also showed how separating responsibilities can lead to simpler and more maintainable tests and production code.&lt;/p&gt;

&lt;p&gt;The original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; was responsible both for coordinating multiple external endpoints to open a claim and for handling and handling all possible errors. 
To avoid having to write cumbersome integration tests for the error handling, we had introduced “testing-only” interfaces, 
which made the resulting tests easier to write, but more sensitive to structural changes, even when behaviour remained the same.&lt;/p&gt;

&lt;p&gt;We decided to separate the two responsibilities by introducing a decorator that took over the error handling logic, and allowed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; 
to focus exclusively on orchestrating the claim opening process. 
This separation made each responsibility explicit in production code and allowed the error-handling logic to be tested in isolation.&lt;/p&gt;

&lt;p&gt;As a result, the tests for error handling became simpler and more robust. 
They had a much better &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; because they were only coupled 
to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; interface, the entry point to the role of &lt;em&gt;opening a claim in a company&lt;/em&gt;. 
This decoupling made it possible to materialise the three former peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeCompanyApi&lt;/code&gt; and remove the unnecessary interfaces altogether. 
At the same time, by using test doubles to simulate that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanyApi&lt;/code&gt; raises exceptions, we could still avoid writing cumbersome broad integration tests.&lt;/p&gt;

&lt;p&gt;Both production code and tests became easier to evolve and maintain because separating responsibilities made each component’s responsibility explicit and reduced coupling between them. 
However, notice that these benefits came at the price of having to pay careful attention when composing the object graph, because an incorrect composition could lead to unexpected behaviour. 
To avoid this problem, we should complement unit tests with at least one integration test that explicitly validates the composed behaviour. 
Doing this improves the &lt;a href=&quot;https://www.youtube.com/watch?v=7o5qxxx7SmI&quot;&gt;predictability&lt;/a&gt; of the tests.&lt;/p&gt;

&lt;p&gt;In a future post, we’ll show how AI helped in both the introduction of the decorator to separate responsibilities and the later simplifications made possible by the new design.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and  &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt; 
for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@cottonbro/&quot;&gt;Cottonbro Studio&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://testdesiderata.com/&quot;&gt;Test Desiderata&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://emmanuelvalverderamos.substack.com/p/materialization-turning-a-false-peer&quot;&gt;Materialization: turning a false peer into an internal&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt; and  &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1]  &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt; and I talked about &lt;strong&gt;materialisation&lt;/strong&gt; in the post: &lt;a href=&quot;https://emmanuelvalverderamos.substack.com/p/materialization-turning-a-false-peer&quot;&gt;Materialization: turning a false peer into an internal&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2026-02-22T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/02/separating-responsibilities-with-decorator</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/02/separating-responsibilities-with-decorator</guid>
        </item>
      
    
      
        <item>
          <title>Bundling up to reduce coupling and complexity (peer detection techniques)</title>
          <description>&lt;h2 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h2&gt;

&lt;p&gt;In previous posts&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; we have talked about the importance of distinguishing an object’s peers from its internals in order to write maintainable unit tests, and how the &lt;strong&gt;peer-stereotypes&lt;/strong&gt; help us detect an object’s peers.&lt;/p&gt;

&lt;p&gt;We also presented three techniques, described in the &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS&lt;/a&gt; book, to detect &lt;strong&gt;object and value types&lt;/strong&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Breaking out&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bundling up&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Budding off&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;and explained in depth one of them: &lt;strong&gt;breaking out&lt;/strong&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/object-detection-techniques-goos_transparent.png&quot; alt=&quot;How we detect the need and the mechanism used to apply each of the techniques.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;How we detect the need and the mechanism used to apply each of the techniques&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In this post we focus on the &lt;strong&gt;bundling up&lt;/strong&gt; technique.&lt;/p&gt;

&lt;h2 id=&quot;2-bundling-up&quot;&gt;2. &lt;strong&gt;Bundling up&lt;/strong&gt;.&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;bundling up&lt;/strong&gt; technique is an application of the &lt;strong&gt;“Composite Simpler Than the Sum of Its Parts”&lt;/strong&gt; rule of thumb that the &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS&lt;/a&gt; authors describe in chapter 6, &lt;em&gt;Object-Oriented Style&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that “composite” refers to “&lt;a href=&quot;https://dictionary.cambridge.org/dictionary/english/composite&quot;&gt;something made of various parts&lt;/a&gt;”. In this post, the terms &lt;strong&gt;“composite type”&lt;/strong&gt; and &lt;strong&gt;“composite abstraction”&lt;/strong&gt; refer to &lt;strong&gt;a type composed of other types.&lt;/strong&gt; They should not be confused with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Composite_pattern&quot;&gt;composite design pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS&lt;/a&gt; authors explain that when we compose object or value types to create a composite type, our goal is for the resulting type to exhibit behaviour simpler than that of its components taken together. This means that the composite should reduce complexity rather than merely aggregate it. To achieve this, the composite type’s API should hide its internal components and their interactions, and expose a simpler abstraction to its consumers, (following the &lt;a href=&quot;https://wiki.c2.com/?InformationHiding&quot;&gt;Information Hiding principle&lt;/a&gt;), which simplifies its consumers.&lt;/p&gt;

&lt;p&gt;In short, the &lt;strong&gt;“Composite Simpler Than the Sum of Its Parts”&lt;/strong&gt; rule of thumb states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“The API of a composite object should not be more complicated than that of any of its components.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This rule of thumb is useful for evaluating the outcome of a refactoring that was intended to eliminate complexity by introducing a new abstraction.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;bundling up&lt;/strong&gt; technique can be used to detect both object and value types.&lt;/p&gt;

&lt;h3 id=&quot;2-1-detecting-value-types&quot;&gt;2. 1. Detecting value types.&lt;/h3&gt;

&lt;p&gt;For value types, &lt;strong&gt;bundling up&lt;/strong&gt; consist in detecting and eliminating existing &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=10&quot;&gt;data clumps&lt;/a&gt; through refactoring&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-2-detecting-object-types&quot;&gt;2. 2. Detecting object types.&lt;/h3&gt;

&lt;p&gt;For objects, &lt;strong&gt;bundling up&lt;/strong&gt; consist in hiding related objects into a containing object.&lt;/p&gt;

&lt;p&gt;Whenever we observe a cluster of related collaborator objects working together to fulfill a specific responsibility for their consumer, it might be a signal of an implicit concept. We can make this concept explicit by introducing a new composite object type that will package the cluster of related collaborator objects up.&lt;/p&gt;

&lt;p&gt;This composite object hides the complexity of the cluster behind an abstraction that allows us to program at a higher level. This not only improves cohesion, but also reduces coupling since consumers only interact with the new composite object.&lt;/p&gt;

&lt;p&gt;Furthermore, the new abstraction enhances domain clarity because it more clearly delimits the scope of the cluster of related objects more clearly, and naming it clarifies the underlying concept it represents. At the same time, it shields its consumers from the interactions between the objects in the packaged cluster to fulfill their responsibility.&lt;/p&gt;

&lt;h4 id=&quot;2-2-1-how-do-we-apply-a-bundling-up&quot;&gt;2. 2. 1. How do we apply a &lt;strong&gt;bundling up&lt;/strong&gt;?&lt;/h4&gt;

&lt;p&gt;We introduce a new composite object that bundles up some object’s peers through refactoring. The process would be as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We create an instance of the new composite object in the constructor of the object for which the related cluster of peers played a specific role, and store that instance in a field. We should inject those peers into the new composite object’s through its constructor when creating its instance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We move the composite behaviour into the new object. We may need to segregate that behaviour first&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this refactoring, the new composite object is an internal of the object from which it was extracted. Consequently, introducing it does not affect the tests, because they are not coupled to it and already cover its behaviour.&lt;/p&gt;

&lt;h4 id=&quot;2-2-2-signals-that-a-bundling-up-is-necessary&quot;&gt;2. 2. 2. Signals that a &lt;strong&gt;bundling up&lt;/strong&gt; is necessary.&lt;/h4&gt;

&lt;p&gt;There are two ways to notice that a &lt;strong&gt;bundling up&lt;/strong&gt; is necessary:&lt;/p&gt;

&lt;p&gt;a. Detecting code smells in production code.&lt;/p&gt;

&lt;p&gt;We may detect that the object using the cluster of related collaborating objects code suffers from the &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=7&quot;&gt;divergent change code smell&lt;/a&gt; which points to a cohesion problem, the class has too many responsibilities.&lt;/p&gt;

&lt;p&gt;In chapter 20, of his &lt;a href=&quot;https://www.oreilly.com/library/view/working-effectively-with/0131177052/&quot;&gt;Working effectively with legacy code&lt;/a&gt; book, Michael Feather explains several heuristics to identify responsibilities in a class. Some of them might prove useful to identify clusters of fields and private methods that are being used together to fulfill a responsibility that is not the main responsibility of the class&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;. If most of the fields in the cluster are peers, we have found a candidate cluster for applying a &lt;strong&gt;bundling up&lt;/strong&gt;. Notice that those clusters might be hidden by &lt;a href=&quot;https://web.archive.org/web/20220516190447/https://www.informit.com/articles/article.aspx?p=102271&amp;amp;seqNum=3&quot;&gt;long methods&lt;/a&gt;, so we may need to decompose those first.&lt;/p&gt;

&lt;p&gt;b. Detecting testability problems.&lt;/p&gt;

&lt;p&gt;These testability problems will appear in the tests of the object for which the related collaborators in the cluster act as peers. We’ll notice that the test setup becomes overly complex because we need to simulate too many peers (and possibly supply additional configuration) just to get the object under test into a relevant state. The authors of the &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS book&lt;/a&gt; illustrate this situation when describing the &lt;strong&gt;“Bloated Constructor”&lt;/strong&gt; test smell in chapter 20 of the book, which is devoted to test smells that may indicate design problems&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tests might be especially painful to maintain, if there’s still some churn&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt; in the interfaces of the peers, or in their interactions to fulfill their composite responsibility because the tests are coupled with them and that churn will affect them.&lt;/p&gt;

&lt;p&gt;Take in mind that this signal might take longer to be noticeable than detecting code smells in the production code, but when it appears it points to a stronger need to to &lt;strong&gt;bundle up&lt;/strong&gt; some of the object’s peers.&lt;/p&gt;

&lt;p&gt;If we are suffering testability problems, extracting a new internal composite object won’t be enough, we’ll also need to promote the new composite object to be a peer and refactor the tests.&lt;/p&gt;

&lt;h4 id=&quot;-2-2-3-refactoring-the-tests&quot;&gt;&lt;a name=&quot;refactoring_tests&quot;&gt;&lt;/a&gt; 2. 2. 3. Refactoring the tests.&lt;/h4&gt;

&lt;p&gt;We promote the internal composite object to be a peer of the object that uses it by introducing an interface for the role it plays, then invert the dependency on it, and inject it through the constructor of the object that uses it.&lt;/p&gt;

&lt;p&gt;Then we refactor the tests, to simplify them:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We test the new composite object directly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We use test doubles to simulate the behaviour of the composite in the tests of the code from which it was extracted.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the case of a &lt;strong&gt;bundling up&lt;/strong&gt;, promoting the internal composite object to be a peer won’t reduce the &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; of the tests, as was the case for a &lt;strong&gt;breaking out&lt;/strong&gt;. This happens because a &lt;strong&gt;bundling up&lt;/strong&gt; reduces the overall coupling.&lt;/p&gt;

&lt;p&gt;Imagine that we have an object that has 5 peers, 3 of which form a cluster that work together to fulfill some responsibility for the object. If we &lt;strong&gt;bundle up&lt;/strong&gt; the cluster in a new composite object and make it a peer, the object will now have 3 peers (2 original peers that were not part of the cluster + the new composite object) instead of the original 5. This means that when there are testability problems making the new composite object a peer makes sense because it increases the &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; of the tests&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, the tests using the interface of the composite object directly will be more focused which will improve the overall tests’ &lt;a href=&quot;https://www.youtube.com/watch?v=bDaFPACTjj8&quot;&gt;readability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=CAttTEUE9HM&quot;&gt;writability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;specificity&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tests of the client of the new abstraction will also be more maintainable because the new abstraction shields its consumers from any churn inside it, i. e., changes in the interfaces or interactions between the peers the abstraction is bundling up. This is one of the advantages of &lt;a href=&quot;https://wiki.c2.com/?InformationHiding&quot;&gt;information hiding&lt;/a&gt;. We benefit even more from this protection while the functionality within the cluster is still actively evolving.&lt;/p&gt;

&lt;p&gt;As in the case of &lt;strong&gt;breaking out&lt;/strong&gt;, we prefer to promote the new internal composite object to peer only if we are experiencing testability problems. Otherwise, we keep it as an internal to avoid coupling tests to an abstraction that might prove unnecessary, in case coupling to it ends up providing no benefits.&lt;/p&gt;

&lt;h2 id=&quot;3-an-example&quot;&gt;3. An example.&lt;/h2&gt;

&lt;p&gt;Some time ago, we were developing an application that processed clicks on ads in different portals and associated them to the campaign they should be charged to using several criteria.&lt;/p&gt;

&lt;h3 id=&quot;3-1-before-applying-a-bundling-up&quot;&gt;3. 1. Before applying a &lt;strong&gt;bundling up&lt;/strong&gt;.&lt;/h3&gt;

&lt;p&gt;Early in the development of the application we had a design like the one shown the following diagram:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/bundling-up/clickProcessor_before_before_bundling.png&quot; alt=&quot;Initial design with many peers.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Initial design with many peers.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; class had 7 collaborators, of which 6 were peers&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourcesMapGenerator&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DomainLogger&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickRecording&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsMapping&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsRepository&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EuroExchangeService&lt;/code&gt;), and 1 was an internal, (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MessageComposer&lt;/code&gt;), that in turn had two peers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UniqueIdGenerator&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The 6 peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; and the 2 peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MessageComposer&lt;/code&gt; matched the &lt;strong&gt;dependency role stereotype&lt;/strong&gt;. They were &lt;strong&gt;ports&lt;/strong&gt; of the application.&lt;/p&gt;

&lt;p&gt;This meant that the unit tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; had to use 8 test doubles to simulate the behaviour of the 8 dependencies.&lt;/p&gt;

&lt;p&gt;Since the application was still in flux as we iterated to add new sources of campaigns and ads, the logic in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; was evolving rapidly and soon we would need to add new peers to retrieve information from new sources. This churn transmitted to the tests that had to keep up with the changes in logic and peers. The complicated set up of the tests and that churn were causing us a lot of pain.&lt;/p&gt;

&lt;p&gt;As their names indicate, two of the peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; were related to campaigns: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsMapping&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also observed that most of the churn in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; was coming from iterations to evolve the logic to retrieve the campaign to which a given click was assigned. Furthermore, we also knew that this campaign retrieval logic was soon to grow to support new sources for campaigns and ads coming from two recently acquired companies.&lt;/p&gt;

&lt;p&gt;There were three peers working together to retrieve the campaign to which an ad was assigned: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsMapping&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsRepository&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EuroExchangeService&lt;/code&gt;. We decided to &lt;strong&gt;bundle up&lt;/strong&gt; this cluster to shield ourselves from churn in the campaign retrieval logic, reduce coupling and improve test maintainability. Consequently,  we extracted a new composite object, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; which encapsulated the cluster and was responsible for retrieving the campaign.&lt;/p&gt;

&lt;h3 id=&quot;3-2-after-introducing-the-new-composite-type&quot;&gt;3. 2. After introducing the new composite type.&lt;/h3&gt;

&lt;p&gt;The new composite type, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt;, was an internal of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt;. The resulting design is shown in the following diagram:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/bundling-up/clickProcessor_before_bundling.png&quot; alt=&quot;Design after introducing the new composite object.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Design after introducing the new composite object.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; had 5 collaborators, of which 3 were peers, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourcesMapGenerator&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DomainLogger&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickRecording&lt;/code&gt;; and 2 were internals:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MessageComposer&lt;/code&gt; which in turn had 2 peers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UniqueIdGenerator&lt;/code&gt;; and&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; which in turn had 3 peers also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsMapping&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignsRepository&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EuroExchangeService&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This refactoring reduced the overall coupling because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; went from having 7 collaborators to having 5. As we explained in a previous section, the coupling reduction is equal to the number of peers bundled in the new composite object minus one, in this case, 3 – 1 = 2.&lt;/p&gt;

&lt;p&gt;Since, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; was still an internal of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt;, the tests didn’t change after this refactoring.&lt;/p&gt;

&lt;h3 id=&quot;3-3-after-promoting-the-new-composite-type-to-be-a-peer&quot;&gt;3. 3. After promoting the new composite type to be a peer.&lt;/h3&gt;

&lt;p&gt;Finally, we promoted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; to be a peer and simplified the tests (the details of this refactoring in section &lt;a href=&quot;#refactoring_tests&quot;&gt;2. 2. 3. Refactoring the tests&lt;/a&gt;). The resulting design is shown in the following diagram:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/bundling-up/clickProcessor_after_bundling.png&quot; alt=&quot;Design after promoting to peer the new composite object.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Design after promoting to peer the new composite object.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;After this final refactoring, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; class still had 5 collaborators, but now 4 of them were peers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourcesMapGenerator&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DomainLogger&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickRecording&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt;), and only 1 was an internal, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MessageComposer&lt;/code&gt; which in turn had 2 peers: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UniqueIdGenerator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; became much simpler: they were coupled to 6 peers instead of the 8 before the refactoring and therefore required only 6 test doubles. This reduction in coupling was reflected in the tests, which became more focused and were shielded from the churn in the campaign retrieval logic.&lt;/p&gt;

&lt;p&gt;The campaign retrieval logic resided in the class implementing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; interface, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotYetUsingDataApiCampaignRetrieval&lt;/code&gt;, (a temporary name reflecting that we were still iterating its behavior). Its focused tests were the only ones affected by ongoing changes in the campaign retrieval code.&lt;/p&gt;

&lt;p&gt;Reducing the number of peers of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickProcessor&lt;/code&gt; by 2 may not seem much, but shielding its tests from the churn in the campaign retrieval logic made a big difference for us, because it removed the high maintenance burden of having to update them every time a small change happened in the campaign retrieval code.&lt;/p&gt;

&lt;p&gt;Eventually the logic to retrieve a campaign grew in complexity until it became a subsystem in its own right, thus having applied a &lt;strong&gt;bundling up&lt;/strong&gt; to that initial cluster of 3 objects proved to be a very successful bet&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/bundling-up/campaign_retrieval_subsystem.png&quot; alt=&quot;CampaignRetrieval subsystem.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;CampaignRetrieval subsystem.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This table summarizes the reduction in complexity on this stage of the process.&lt;/p&gt;

&lt;table class=&quot;zebraTable&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Stage&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;ClickProcessor&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;ClickProcessor test&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Complexity&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;strong&gt;Before bundling up&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1 internal (2 peers) + 6 peers, 8 peers in total&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;8 test doubles&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Many peers, high coupling to tests&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;strong&gt;After introducing composite&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1 internal (2 peers) + 1 internal (3 peers) + 3 peers, 8 peers in total&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;8 test doubles&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Better cohesion, same coupling to tests&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;strong&gt;After promoting composite to peer&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1 internal (with 2 peers) + 4 peers, 8 peers in total&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;6 test doubles&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Same cohesion as previous stage, reduced coupling to tests: improved testability&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;figcaption&gt;&lt;strong&gt;Stages showing a reduction in complexity.&lt;/strong&gt;&lt;/figcaption&gt;

&lt;h2 id=&quot;4-conclusions&quot;&gt;4. Conclusions.&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;bundling up&lt;/strong&gt; technique is a refactoring that manages and reduces complexity by grouping related collaborators into a single composite object. It is an application of the &lt;strong&gt;“Composite Simpler Than the Sum of Its Parts”&lt;/strong&gt; rule of thumb. Rather than merely aggregating objects, the goal of &lt;strong&gt;bundling up&lt;/strong&gt; is to create a higher-level abstraction that makes the design simpler to understand, reason about, and use.&lt;/p&gt;

&lt;p&gt;This technique can be applied to both value and object types. In the case of values, &lt;strong&gt;bundling up&lt;/strong&gt; involves detecting and eliminating &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=10&quot;&gt;data clumps&lt;/a&gt; by introducing meaningful abstractions that represent them explicitly. For objects, it consists of identifying clusters of collaborators that work together to fulfill a specific responsibility and packaging them inside a new composite object. By doing so, implicit concepts are turned into explicit abstractions with clear boundaries and well-defined responsibilities.&lt;/p&gt;

&lt;p&gt;Applying &lt;strong&gt;bundling up&lt;/strong&gt; brings several important design benefits. It improves &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;cohesion&lt;/a&gt; by isolating a distinct responsibility within its own abstraction, and it reduces coupling because clients interact with one composite object instead of many individual objects. It also improves domain clarity, since naming the new abstraction helps reveal the underlying concept it represents. At the same time, it strengthens &lt;a href=&quot;https://wiki.c2.com/?InformationHiding&quot;&gt;information hiding&lt;/a&gt; by shielding consumers from internal interactions and future changes within the packaged cluster of objects.&lt;/p&gt;

&lt;p&gt;In the case of object types, there are signals that indicate when &lt;strong&gt;bundling up&lt;/strong&gt; may be necessary. In production code, code smells such as &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=7&quot;&gt;divergent change&lt;/a&gt;, &lt;a href=&quot;https://web.archive.org/web/20220516190447/https://www.informit.com/articles/article.aspx?p=102271&amp;amp;seqNum=3&quot;&gt;long methods&lt;/a&gt;, or &lt;a href=&quot;https://web.archive.org/web/20220524180212/https://www.informit.com/articles/article.aspx?p=102271&amp;amp;seqNum=4&quot;&gt;large classes&lt;/a&gt; often point to hidden clusters of related behaviour. In tests, the need for &lt;strong&gt;bundling up&lt;/strong&gt; becomes apparent when setup logic grows complicated requiring many test doubles, or when tests become fragile because they are tightly coupled to a cluster of collaborating objects in churn. These testability problems are strong indicators that an implicit abstraction should be made explicit.&lt;/p&gt;

&lt;p&gt;The refactoring process typically involves introducing a new composite object, injecting the relevant peers into it, and moving the related behavior into this new abstraction. Initially, the composite can remain an internal of the original object, leaving existing tests unchanged. If testability problems persist, the composite can then be promoted to an explicit peer, which usually simplifies tests by reducing the number of awkward collaborators they must simulate. Unlike &lt;strong&gt;breaking out&lt;/strong&gt;, &lt;strong&gt;bundling up&lt;/strong&gt; tends to increase the &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; of the tests because it reduces coupling.&lt;/p&gt;

&lt;p&gt;In summary, &lt;strong&gt;bundling up&lt;/strong&gt; is an effective way to uncover meaningful abstractions, control complexity, and improve maintainability in both code and tests. Even small reductions in coupling can have a significant impact when they shield consumers from volatile parts of the system. As shown in the example, a well-chosen composite may naturally evolve into a subsystem, confirming the value of &lt;strong&gt;bundling up&lt;/strong&gt; as a long-term investment to create a more sustainable design.&lt;/p&gt;

&lt;p&gt;Our next post in this series will focus on the &lt;strong&gt;budding off&lt;/strong&gt; technique.&lt;/p&gt;

&lt;p&gt;Thanks for reading to the end of this post. We hope the ideas presented here prove useful in your own work.&lt;/p&gt;

&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;

&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@cottonbro/&quot;&gt;Cottonbro Studio&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/35957157-thinking-in-bets&quot;&gt;Thinking in Bets: Making Smarter Decisions When You Don’t Have All the Facts&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Annie_Duke&quot;&gt;Anne Duke&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://testdesiderata.com/&quot;&gt;Test Desiderata&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] These are the posts mentioned in the introduction:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt; in which we commented, among other things, the importance of distinguishing an object’s peers from its internals in order to write maintainable unit tests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt; in which we explained how the &lt;strong&gt;peer stereotypes&lt;/strong&gt; helped us identify an object’s peers.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] When we use the term &lt;strong&gt;object&lt;/strong&gt; in this post, we are using the meaning from &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software, Guided by Tests (GOOS)&lt;/a&gt; book:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objects&lt;/strong&gt; “have an identity, might change state over time, and model computational processes”. They should be distinguished from &lt;strong&gt;values&lt;/strong&gt; which “model unchanging quantities or measurements” (&lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;value objects&lt;/a&gt;). An &lt;strong&gt;object&lt;/strong&gt; can be an internal or a peer of another &lt;strong&gt;object&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] We devoted two posts to explain the &lt;strong&gt;breaking out&lt;/strong&gt; technique in depth:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;, and its continuation,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking out” (peer detection techniques)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] This mind map comes from a talk which was part of the &lt;strong&gt;Mentoring Program in Technical Practices&lt;/strong&gt; we taught in 2024 in &lt;a href=&quot;https://www.domingoalonsogroup.com/es/empresas/aida&quot;&gt;AIDA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] In the &lt;em&gt;Value Types&lt;/em&gt; section of chapter 7, &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt; of &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS&lt;/a&gt;, the author explains that they apply a &lt;strong&gt;bundling up&lt;/strong&gt; when they detect an instance of the &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=10&quot;&gt;data clump code smell&lt;/a&gt;: “when we notice that a group of values are always used together, we take that as a suggestion that there’s a missing construct”.&lt;/p&gt;

&lt;p&gt;They continue detailing how they refactor it: “A first step might be to create a new type with fixed public fields—just giving the group a name highlights the missing concept. Later we can migrate behaviour to the new type, which might eventually allow us to hide its fields behind a clean interface.”&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] Applying &lt;a href=&quot;https://refactoring.com/catalog/extractFunction.html&quot;&gt;Extract Function/Method&lt;/a&gt; and other related refactorings, see chapter 6, &lt;em&gt;A First Set of Refactorings&lt;/em&gt;, of Martin Fowler’s &lt;a href=&quot;https://martinfowler.com/books/refactoring.html&quot;&gt;Refactoring book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] We think that the following four heuristics to detect responsibilities may be useful to detect clusters collaborating peers and methods: &lt;em&gt;Grouping Methods&lt;/em&gt;, &lt;em&gt;Looking at Hidden Methods&lt;/em&gt;, &lt;em&gt;Decisions that may change&lt;/em&gt; and &lt;em&gt;Internal Relationships&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] You can also find posts explaining these test smells in their old blog under the category: &lt;a href=&quot;https://web.archive.org/web/20210426022938/http://www.mockobjects.com/search/label/listening%20to%20the%20tests&quot;&gt;Listening to the tests&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] In the context of software development, &lt;strong&gt;churn&lt;/strong&gt; refers to &lt;strong&gt;frequent changes&lt;/strong&gt; in the code, interfaces, or design.&lt;/p&gt;

&lt;p&gt;Specifically, in this post, we are talking about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;“Churn in the interfaces”&lt;/strong&gt;: Meaning that the definitions of how different components (peers) communicate are changing often (e.g., method names, parameters, or return types are being modified repeatedly).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;“Churn in their interactions”&lt;/strong&gt;: Referring to frequent changes in how these components collaborate or the sequence of steps they take to achieve a goal.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] If a cluster contains n peers of an object that work together, bundling them into a composite object and making it a peer of the original object will reduce the number of peers the object is coupled with by n – 1 (we remove the n peers in the cluster, but add one new peer: the composite object).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] You can find several practical heuristics that help you decide whether a collaborator should be considered a peer or an internal in the post: &lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12]  When I left the application the implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CampaignRetrieval&lt;/code&gt; already had 5 peers and several internals.&lt;/p&gt;

</description>
          <pubDate>2026-02-15T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/02/bundling-up</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/02/bundling-up</guid>
        </item>
      
    
      
        <item>
          <title>¡&quot;Isolated&quot; test significa algo muy diferente para distintas personas!</title>
          <description>&lt;p&gt;Este post es una traducción del post original en inglés: &lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;

&lt;p&gt;Un concepto que encontramos muy útil tanto cuando hacemos TDD como cuando introducimos tests en código legacy son las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; (&lt;strong&gt;F&lt;/strong&gt;ast, &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable, &lt;strong&gt;S&lt;/strong&gt;elf-validating), que se utilizan para caracterizar un test unitario ideal. Estas propiedades tienen su origen en el acrónimo &lt;strong&gt;FIRST&lt;/strong&gt;, que caracterizan los tests unitarios ideales en el contexto de TDD, en donde la T significa &lt;strong&gt;T&lt;/strong&gt;imely, (“hecho a tiempo”)&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esto es lo que queremos decir con tests &lt;strong&gt;F&lt;/strong&gt;ast, &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable y &lt;strong&gt;S&lt;/strong&gt;elf-validating:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;F&lt;/strong&gt;ast: deberían ejecutarse tan rápido que nunca sintamos la necesidad de ejecutarlos  más tarde.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;I&lt;/strong&gt;solated: deberían producir los mismos resultados independientemente del orden en el que se ejecuten. Esto significa que los tests no dependen unos de otros, ni directa ni indirectamente.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;R&lt;/strong&gt;epeatable: deberían ser deterministas; sus resultados no deberían cambiar si el comportamiento que probamos y el entorno no han cambiado.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;S&lt;/strong&gt;elf-validating: deberían pasar o fallar automáticamente, sin requerir que un humano intervenga para determinar el resultado. Esta propiedad es esencial para la automatización de tests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el contexto de TDD y en el de añadir tests a código legacy, las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; cumplen roles diferentes, en el primer caso nos pueden servir de guía para diseñar unidades testables, mientras que en el segundo nos ayudan a descubrir problemas de testabilidad&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cuando añadimos tests en un código legacy, las violaciones de las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; resaltan aquellas dependencias que dificultan el testing, conocidas como &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt; (awkward collaborations)&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. Estas &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt; serían las dependencias que necesitaríamos romper utilizando &lt;strong&gt;técnicas de rotura de dependencias&lt;/strong&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; para poder introducir tests unitarios.&lt;/p&gt;

&lt;p&gt;En el caso de los tests de integración bastaría centrarse en las violaciones de las propiedades &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable y &lt;strong&gt;S&lt;/strong&gt;elf-validating. Las dependencias que violan las propiedades &lt;strong&gt;R&lt;/strong&gt;epeatable y &lt;strong&gt;S&lt;/strong&gt;elf-validating requieren de la aplicación de &lt;strong&gt;técnicas de rotura de dependencias&lt;/strong&gt;, mientras que las violaciones de la propiedad &lt;strong&gt;I&lt;/strong&gt;solated a menudo también pueden resolverse usando otros enfoques, como &lt;a href=&quot;http://xunitpatterns.com/test%20fixture%20-%20xUnit.html&quot;&gt;fixtures&lt;/a&gt; específicas para tests o cambios de configuración.&lt;/p&gt;

&lt;p&gt;En el contexto de TDD, las violaciones de las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; son una heurística clave para identificar aquellas colaboraciones que necesitamos empujar fuera de la unidad bajo test. Estas &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt; las simularemos con dobles de prueba en nuestros tests unitarios.&lt;/p&gt;

&lt;p&gt;Cuando hacemos TDD, identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt; es más difícil porque debemos inferirlas a partir de la especificación. En cambio, en el código legacy son más fáciles de identificar porque las vemos en el código y además se manifiestan a través de los problemas de testabilidad que causan.&lt;/p&gt;

&lt;p&gt;Identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt; es, por tanto, una habilidad importante para poder diseñar código testable. En este sentido, las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; resultan una valiosa guía para definir los límites de una unidad, y nos ayudan a desarrollar código testable.&lt;/p&gt;

&lt;h2 id=&quot;parece-que-isolated-test-significa-algo-muy-diferente-para-distintas-personas&quot;&gt;¡Parece que “isolated test” significa algo muy diferente para distintas personas!&lt;/h2&gt;

&lt;figure style=&quot;margin:auto; width: 70%&quot;&gt;
&lt;img src=&quot;/assets/isolated_meme.jpg&quot; alt=&quot;Isolated. Sigues usando esa palabra. No creo que signifique lo que tú crees que significa.&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Si lees la definición original de &lt;strong&gt;isolated&lt;/strong&gt; en &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;Agile in a Flash:  F.I.R.S.T.&lt;/a&gt;
notarás que es diferente de lo que nosotros hemos expresado en la sección anterior.&lt;/p&gt;

&lt;p&gt;Para nosotros &lt;strong&gt;isolated&lt;/strong&gt; significa que “un test debería producir los mismos resultados independientemente del orden en el que se ejecute.
Esto significa que los tests no dependen unos de otros de ninguna manera, ni directa ni indirectamente”.&lt;/p&gt;

&lt;p&gt;En la definición de &lt;strong&gt;isolated&lt;/strong&gt; de &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;Agile in a Flash:  F.I.R.S.T.&lt;/a&gt;, la flash card afirma:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Isolated: Failure reasons become obvious.” (Isolated: Las razones del fallo se vuelven evidentes)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Más adelante, en la explicación, elaboran lo que esto significa (el énfasis en negrita fue añadido por nosotros):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Isolated: Tests isolate failures. A developer should never have to reverse-engineer tests or the code being tested to know what went wrong. Each test class name and test method name with the text of the assertion should state exactly what is wrong and where. If a &lt;strong&gt;test&lt;/strong&gt; does not &lt;strong&gt;isolate failures&lt;/strong&gt;, it is best to replace that test with smaller, more-specific tests. (Isolated: Los tests aíslan los fallos. Un desarrollador nunca debería tener que hacer ingeniería inversa de los tests o del código que se está probando para saber qué salió mal. El nombre de cada clase de test y de cada método de test, junto con el texto de la aserción, debería indicar exactamente qué está mal y dónde. Si un &lt;strong&gt;test&lt;/strong&gt; no &lt;strong&gt;aísla fallos&lt;/strong&gt;, es mejor reemplazarlo por tests más pequeños y más específicos.)&lt;/p&gt;

  &lt;p&gt;A good unit test has &lt;strong&gt;a laser-tight focus on a single effect or decision in the system under test&lt;/strong&gt;. And that system under test tends to be a single part of a single method on a single class (hence “unit”). &lt;strong&gt;Tests must not have any order-of-run dependency&lt;/strong&gt;. They should pass or fail the same way in suite or when run individually. Each suite should be re-runnable even if tests are renamed or reordered randomly. &lt;strong&gt;Good tests interfere with no other tests in any way&lt;/strong&gt;. &lt;strong&gt;They impose their initial state without aid from other tests&lt;/strong&gt;. &lt;strong&gt;They clean up after themselves&lt;/strong&gt;.” (Un buen test unitario &lt;strong&gt;se centra de forma extremadamente precisa en un único efecto o decisión en el sistema bajo test&lt;/strong&gt;. Y ese sistema bajo test suele ser una parte única de un único método en una única clase (de ahí “unit”). &lt;strong&gt;El resultado de los tests no debe depender del orden de ejecución&lt;/strong&gt;. Deberían pasar o fallar de la misma manera al ejecutarse en una suite o de forma individual. Cada suite debería poder ejecutarse de nuevo incluso si los tests se renombran o se reordenan aleatoriamente. &lt;strong&gt;Unos tests bien hechos no interfieren con otros tests de ninguna manera&lt;/strong&gt;. &lt;strong&gt;Imponen su estado inicial sin la ayuda de otros tests&lt;/strong&gt;. &lt;strong&gt;Limpian su entorno después de ser ejecutados&lt;/strong&gt;.”)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt; en &lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt; lo resume así:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Isolated - tests don’t rely upon either other in any way, including indirectly. Each test isolates one failure mode only.” (Isolated - los tests no dependen unos de otros de ninguna manera, ni siquiera indirectamente. Cada test aísla un único modo de fallo.)&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por contra, para nosotros &lt;strong&gt;isolated&lt;/strong&gt;, en el contexto de identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt;, significa que los tests deberían estar aislados entre sí, lo que, en la práctica, significa que no pueden compartir ningún estado o recurso mutable. Nuestra definición es menos restrictiva que la de Ottinger. Elegimos considerar sólo un aspecto de su definición, que “los tests no interfieren con otros tests de ninguna manera”, y no el otro, “los tests tienen una única razón para fallar” (comentaremos más sobre este otro aspecto más abajo).&lt;/p&gt;

&lt;p&gt;Creemos que lo que nosotros entendemos por &lt;strong&gt;isolated&lt;/strong&gt; se alinea con la definición que Kent Beck proporciona en su libro &lt;a href=&quot;https://www.oreilly.com/library/view/test-driven-development/0321146530/&quot;&gt;Test Driven Development: By Example&lt;/a&gt;. En la sección &lt;em&gt;Isolated Test&lt;/em&gt; (página 125) del capítulo &lt;em&gt;Test-Driven Development Patterns&lt;/em&gt;, escribe:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“How should the running of tests affect one another? Not at all.” (¿Cómo debería afectar los tests unos a otros al ser ejecutados? Nada en absoluto.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[…] the main lesson […] tests should be able to ignore one another completely.” ([…] la lección principal […] los tests deberían poder ignorarse unos a otros completamente.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“One convenient implication of isolated tests is that the tests are order independent.” (Una implicación conveniente de los tests isolated es que son independientes del orden.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Además, en su trabajo más reciente &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt; define &lt;strong&gt;isolated&lt;/strong&gt; como:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“tests should return the same results regardless of the order in which they are run”&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt; (los tests deberían dar los mismos resultados independientemente del orden en el que se ejecuten).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dicho esto, hay otra propiedad deseable para los tests en &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt; que resulta interesante para esta discusión, &lt;strong&gt;specificity&lt;/strong&gt;, que Kent Beck explica como:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Specific: if a test fails, the cause of the failure should be obvious.”  (Specific: si un test falla, la causa del fallo debería ser obvia)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Creemos que el segundo aspecto de &lt;strong&gt;isolated&lt;/strong&gt; que aparece en la definición de Ottinger, &lt;strong&gt;tener una única razón para fallar&lt;/strong&gt;, corresponde al nivel más alto posible de especificidad de Beck. Por tanto, parece que lo que Ottinger entiende por &lt;strong&gt;isolated&lt;/strong&gt; estaría incluyendo dos de las propiedades deseables para los tests de las que Beck habla en &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;la propiedad de devolver los mismos resultados independientemente del orden en el que se ejecuten (ser &lt;strong&gt;isolated&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;la propiedad de que los fallos de los tests tengan una causa obvia (ser &lt;strong&gt;specific&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tener una única razón para fallar sigue siendo una propiedad altamente deseable que nosotros también tenemos en cuenta al escribir casos de test. Nos puede ayudar tanto a detectar cuando componer comportamientos independientes, como a evitar la sobreespecificación de algunos tests&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sin embargo, en el contexto de identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt;, hemos encontrado que la definición de &lt;strong&gt;isolated&lt;/strong&gt; de Beck es más útil,
para evitar caer en &lt;strong&gt;la trampa de considerar que la unidad es la clase&lt;/strong&gt;, y para enseñar el uso de los dobles de prueba como herramientas de aislamiento, 
el uso principal en el estilo clásico de TDD.&lt;/p&gt;

&lt;h2 id=&quot;resumen&quot;&gt;Resumen.&lt;/h2&gt;

&lt;p&gt;Mostramos cómo las &lt;strong&gt;propiedades FIRS&lt;/strong&gt; pueden resultar valiosas tanto al hacer TDD como al añadir tests en código legacy, porque nos guían a desarrollar código más testable y mantenible.&lt;/p&gt;

&lt;p&gt;Exploramos cómo el concepto de tests &lt;strong&gt;isolated&lt;/strong&gt; difiere según el autor. Mientras que la definición de Kent Beck enfatiza la independencia entre tests, asegurando que estos produzcan resultados consistentes independientemente del orden de ejecución, la definición que encontramos en &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;F.I.R.S.T in Agile in a Flash&lt;/a&gt; establece además que los tests deberían tener una única razón para fallar. Creemos que esta última definición mezcla la definición de &lt;strong&gt;isolation&lt;/strong&gt; de Beck con otra propiedad de los tests: &lt;strong&gt;specificity&lt;/strong&gt;, ya que tener una única razón para fallar representa el nivel más alto de &lt;strong&gt;specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Pensamos que tanto la definición de &lt;strong&gt;isolated&lt;/strong&gt; de Beck como la de Ottinger son valiosas. Sin embargo, la versión de Beck se alinea más estrechamente con lo que nosotros entendemos por &lt;strong&gt;isolated&lt;/strong&gt; en el contexto de identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt;. Para nosotros, la definición de Beck ha demostrado ser especialmente útil para identificar &lt;strong&gt;colaboraciones incómodas&lt;/strong&gt;, evitar caer en &lt;strong&gt;la trampa de considerar que la unidad es la clase&lt;/strong&gt;, y &lt;strong&gt;enseñar&lt;/strong&gt; cómo usar los &lt;strong&gt;dobles de prueba&lt;/strong&gt; como herramientas de aislamiento.&lt;/p&gt;

&lt;h2 id=&quot;la-serie-sobre-tdd-dobles-de-prueba-y-diseño-orientado-a-objetos&quot;&gt;La serie sobre TDD, dobles de prueba y diseño orientado a objetos.&lt;/h2&gt;

&lt;p&gt;Este post forma parte de una serie sobre TDD, test doubles y diseño orientado a objetos:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/09/mockist-tdd-la-clase-no-es-la-unidad&quot;&gt;La clase no es la unidad en el estilo de TDD de Londres&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;¡”Isolated” test significa algo muy diferente para distintas personas!&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Me gustaría agradecer a &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/franiglesias/&quot;&gt;Fran Iglesias Gómez&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio De La Torre&lt;/a&gt;
por darme feedback sobre varios borradores de este post.&lt;/p&gt;

&lt;p&gt;Finalmente, también me gustaría agradecer a &lt;a href=&quot;https://imgflip.com/&quot;&gt;imgflip&lt;/a&gt; por su &lt;a href=&quot;https://imgflip.com/memegenerator/294538550/Hi-Res-Inconceivable-Inigo-Montoya&quot;&gt;Inconceivable Iñigo Montoya Meme Generator&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;F.I.R.S.T in Agile in a Flash&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/jefflangr/&quot;&gt;Jeff Langr&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/pragmatic-programmers/unit-tests-are-first-fast-isolated-repeatable-self-verifying-and-timely-a83e8070698e&quot;&gt;Unit Tests Are FIRST: Fast, Isolated, Repeatable, Self-Verifying, and Timely&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/jefflangr/&quot;&gt;Jeff Langr&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://jbazuzicode.blogspot.com/2016/07/pure-unit-test-vs-firstness.html&quot;&gt;“pure unit test” vs. “FIRSTness”&lt;/a&gt;, &lt;a href=&quot;https://jay.bazuzi.com/&quot;&gt;Jay Bazuzi&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/test-driven-development/0321146530/&quot;&gt;Test Driven Development: By Example&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HApI2cspQus&quot;&gt;Test Desiderata 8/12: Tests Should Be Isolated (from each other)&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;Test Desiderata 10/12: Tests Should be Specific&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.google.com/document/d/1C85clIy1ZoytjeogApsjCQTdX5aiwo6YcqgCFn8lh20/edit?usp=sharing&quot;&gt;Notes on isolated tests according to Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.google.com/document/d/1QCkJ4WeC4cXy95xXHAEP6iVzTp_1KE5vpTqJVeDJz_I/edit?usp=sharing&quot;&gt;Notes on specific tests according to Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/UnitTest.html&quot;&gt;Unit Test&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/nonDeterminism.html&quot;&gt;Eradicating Non-Determinism in Tests&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=dTRKCXC0JFg&quot;&gt;Princess Bride, “You keep using that word. I do not think it means what you think it means.”&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Lean también el post &lt;a href=&quot;https://jbazuzicode.blogspot.com/2016/07/pure-unit-test-vs-firstness.html&quot;&gt;“pure unit test” vs.
“FIRSTness”&lt;/a&gt; de &lt;a href=&quot;https://jay.bazuzi.com/&quot;&gt;Jay Bazuzi&lt;/a&gt; para aprender más sobre la categorización de tests según su &lt;strong&gt;FIRSness&lt;/strong&gt; (eliminando la &lt;strong&gt;T&lt;/strong&gt;), lo cual puede ser útil al trabajar con código legacy o al hacer tests a posteriori.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Profundizamos en este tema en nuestras formaciones de &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;TDD&lt;/a&gt; y &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] El artículo &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt; de &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Fowler&lt;/a&gt; es el origen del término &lt;strong&gt;colaboración incómoda (awkward collaboration)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Lean nuestro post &lt;a href=&quot;https://codesai.com/posts/2024/03/mindmup-breaking-dependencies&quot;&gt;Classifying dependency-breaking techniques&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Además de resumir muy bien qué significa “Isolated” para ellos, &lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt; profundiza en la historia de cómo surgieron las &lt;strong&gt;propiedades FIRST&lt;/strong&gt; y cómo su significado se ha difuminado con el tiempo. Además, incluye una lista de fuentes que discuten FIRST, destacando los cambios realizados por cada fuente, cómo en el &lt;a href=&quot;https://es.wikipedia.org/wiki/Tel%C3%A9fono_descompuesto&quot;&gt;juego del teléfono roto&lt;/a&gt;, y señalando que algunas ni siquiera dan crédito a los autores originales.&lt;/p&gt;

&lt;p&gt;También hace referencia a otro artículo publicado por &lt;a href=&quot;https://pragprog.com/&quot;&gt;Pragmatic Programmers&lt;/a&gt; como el origen del acrónimo &lt;a href=&quot;https://medium.com/pragmatic-programmers/unit-tests-are-first-fast-isolated-repeatable-self-verifying-and-timely-a83e8070698e&quot;&gt;Unit Tests Are FIRST: Fast, Isolated, Repeatable, Self-Verifying, and Timely&lt;/a&gt;, que creemos que explica FAST aún mejor y ademas incluye ejemplos de código.&lt;/p&gt;

&lt;p&gt;Finalmente, explica el &lt;strong&gt;valor de escribir los tests primero&lt;/strong&gt; y critica escribirlos después.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] &lt;a href=&quot;https://www.linkedin.com/in/ian-cooper-2b059b/&quot;&gt;Ian Cooper&lt;/a&gt;, en su charla &lt;a href=&quot;https://www.youtube.com/watch?v=EZ05e7EMOLM&quot;&gt;TDD, where did it all go wrong&lt;/a&gt;, afirma que:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“For Kent Beck, [a unit test] is a test that runs in isolation from other tests.” (Para Kent Beck, [un test unitario] es un test que se ejecuta de forma aislada respecto a otros tests.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[…] NOT to be confused with the classical unit test definition of targeting a module.” ([…] NO debe confundirse con la definición clásica de test unitario que apunta a un módulo.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;”A lot of issues with TDD is people misunderstanding isolation as class isolation […]” (Muchos de los problemas al hacer TDD provienen de que la gente malinterpreta el aislamiento como aislar la clase […])&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hablamos de este malentendido frecuente, &lt;strong&gt;considerar que la unidad es la clase&lt;/strong&gt;, en nuestro post &lt;a href=&quot;https://codesai.com/posts/2025/09/mockist-tdd-la-clase-no-es-la-unidad&quot;&gt;La clase no es la unidad en el estilo de TDD de Londres&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Puede que escribamos sobre esto en un post futuro.&lt;/p&gt;

</description>
          <pubDate>2026-01-24T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2026/01/isolated-test-algo-diferente-para-personas-diferentes</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2026/01/isolated-test-algo-diferente-para-personas-diferentes</guid>
        </item>
      
    
      
        <item>
          <title>A simple example of the temporary field code smell</title>
          <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction.&lt;/h1&gt;

&lt;p&gt;&lt;a name=&quot;temporary_field_definition&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=16&quot;&gt;Temporary field&lt;/a&gt; is a code smell that occurs when a field is set only at certain times and is null or unused at other times, making the object harder to understand and maintain. This may indicate a deeper design issue.&lt;/p&gt;

&lt;p&gt;Often the issue is a missing abstraction with a different lifecycle. Introducing a semantically meaningful class that includes the field can then clarify responsibilities and remove the code smell.&lt;/p&gt;

&lt;p&gt;Temporary fields can also appear for other reasons. For example, an algorithm may use fields to store temporary data instead of passing it as parameters, which can be fixed by passing data as parameters. They may also result from using the wrong scope for data, which can be fixed by converting the fields into local variables only used where needed.&lt;/p&gt;

&lt;p&gt;In our experience, it can be difficult to find clear examples of this smell online, so we wanted to share one we recently came across&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-example&quot;&gt;The example.&lt;/h1&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3964c37c208e41d11d69fc0b0c82adee.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; class models the outcome of opening a claim, which can succeed or fail. Depending on the outcome, it notifies a different event through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningListener&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; contains two temporary fields: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_referenceInCompany&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_failureDescription&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_referenceInCompany&lt;/code&gt; field is set only when the result is successful and is null when the result is a failure. This field is used exclusively when notifying a success and is never needed when notifying a failure. This makes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_referenceInCompany&lt;/code&gt; a temporary field. In fact, we think that any nullable field in a domain object should always raise our suspicions.&lt;/p&gt;

&lt;p&gt;On the contrary, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_failureDescription&lt;/code&gt; field is set only when the result is failure and is null when the result is a success. This field is used exclusively when notifying a failure and is never needed when notifying a success. This makes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_failureDescription&lt;/code&gt; another temporary field.&lt;/p&gt;

&lt;p&gt;The issue here is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; is trying to model two concepts at the same time: a successful result and a failed result. This issue leads to the temporary fields, and to need to have code that checks which kind of result, failure or success, we are facing in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsFailure()&lt;/code&gt; method&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; and conditional code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notify&lt;/code&gt; method to know what to do in each case.&lt;/p&gt;

&lt;p&gt;All this complexity is the result of two missing abstractions, one to represent the notion of succeeding in opening a claim and another to represent the notion of failing.&lt;/p&gt;

&lt;p&gt;In the next section we’ll show how introducing them will remove not only the two cases of temporary fields, but also the conditional code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notify&lt;/code&gt; and even the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsFailure()&lt;/code&gt; case check.&lt;/p&gt;

&lt;h1 id=&quot;a-refactored-version&quot;&gt;A refactored version.&lt;/h1&gt;

&lt;p&gt;To remove the temporary fields we introduced two new classes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SuccessfulOpeningResult&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FailingOpeningResult&lt;/code&gt;. We did this by applying the &lt;a href=&quot;https://refactoring.com/catalog/introduceSpecialCase.html&quot;&gt;Introduce Special Case&lt;/a&gt; refactoring twice, one for each &lt;a href=&quot;https://martinfowler.com/eaaCatalog/specialCase.html&quot;&gt;special case&lt;/a&gt;: the success and the failure.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a50915da4d71506457c613a063169f96.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After the refactoring each concrete class encapsulates its specific data, (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_referenceInCompany&lt;/code&gt; for success, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_failureDescription&lt;/code&gt; for failure), which removes the temporary fields that introduced ambiguity and confusion.&lt;/p&gt;

&lt;p&gt;The refactored code implements the &lt;a href=&quot;https://martinfowler.com/eaaCatalog/specialCase.html&quot;&gt;Special Case pattern&lt;/a&gt;. It uses polymorphism, dispatching on the kind of result. This removes the need of checking for nulls to know whether we faced a failure or a success, which is why the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsFailure&lt;/code&gt; method and the conditional disappeared&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; is now an abstract class on top of a hierarchy that models the two variations of the notification behaviour. We made &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; an abstract class instead of an interface, because we wanted to keep the two factory methods, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Success&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Failure&lt;/code&gt;, so that we keep clients from coupling to any class that derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt;. This way the clients will only see the abstraction: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary.&lt;/h1&gt;

&lt;p&gt;In this post, we showed a simple code example containing two cases of the temporary field code smell which were caused by a modelling problem.&lt;/p&gt;

&lt;p&gt;We had a class, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpeningResult&lt;/code&gt; that was trying to model two concepts at the same time: success and failure in opening a claim. This flawed modelling required conditional code to select the right behaviour in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notify&lt;/code&gt; method, and led to a case of the &lt;a href=&quot;https://luzkan.github.io/smells/null-check&quot;&gt;null check code smell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We also showed a refactored version which removed both the temporary fields and the null check code smells. We got to that version by applying twice the &lt;a href=&quot;https://refactoring.com/catalog/introduceSpecialCase.html&quot;&gt;Introduce Special Case&lt;/a&gt; refactoring. The final design has a clearer intent and simpler logic which makes it easier to maintain.&lt;/p&gt;

&lt;p&gt;We hope that having more examples of the temporary field code smell may help you to identify and prevent it in your code.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about a draft of this post.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.linkedin.com/in/carlosmiguelseco/&quot;&gt;Carlos Miguel Seco&lt;/a&gt; for giving us the opportunity to work with him on a very interesting project.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@samerdaboul/&quot;&gt;Samer Daboul&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/refactoring-2nd-ed.html&quot;&gt;Refactoring: Improving the Design of Existing Code, 2nd Edition&lt;/a&gt;, Martin Fowler.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://xp123.com/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;, William C. Wake.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2022/11/code-smells-taxonomies-and-catalogs-english&quot;&gt;On code smells catalogues and taxonomies&lt;/a&gt;, Manuel Rivero.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/books/eaa.html&quot;&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;, Martin Fowler.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/eaaCatalog/specialCase.html&quot;&gt;Special Case pattern&lt;/a&gt;, Martin Fowler.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/TellDontAsk.html&quot;&gt;Tell, don’t ask&lt;/a&gt;, Martin Fowler.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://talesfrom.dev/blog/map-dont-ask&quot;&gt;Map, don’t ask&lt;/a&gt;, Damian Płaza&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://java.by-comparison.com/&quot;&gt;Java by Comparison&lt;/a&gt;, Simon Harrer, Jörg Lenhard and Linus Dietz.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Option_type&quot;&gt;Option type&lt;/a&gt;. Wikipedia.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] You can find a more complex example in one of our past posts: &lt;a href=&quot;https://codesai.com/posts/2024/03/using-smells-to-go-oo&quot;&gt;Using code smells to refactor to more OO code (an example with temporary field, solution sprawl and feature envy)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] This method contains an example of the &lt;a href=&quot;https://luzkan.github.io/smells/null-check&quot;&gt;null check code smell&lt;/a&gt; described by Bill Wake in &lt;a href=&quot;https://xp123.com/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Using an &lt;a href=&quot;https://en.wikipedia.org/wiki/Option_type&quot;&gt;Option type&lt;/a&gt; would also be ok only if we use it functionally, “mapping” over it. If, instead, we add some conditional code in which we ask the option type whether we faced a failure or a success, this conditional check would be an example of the &lt;a href=&quot;https://codesai.com/posts/2022/11/code-smells-taxonomies-and-catalogs-english#wake_taxonomy&quot;&gt;special case code smell&lt;/a&gt; described by Bill Wake in &lt;a href=&quot;https://xp123.com/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;. You can read more about using option types functionally in this great post &lt;a href=&quot;https://talesfrom.dev/blog/map-dont-ask&quot;&gt;Map, don’t ask&lt;/a&gt;, or in the section &lt;em&gt;Use Optionals as Streams&lt;/em&gt; of the chapter &lt;em&gt;Let your data flow&lt;/em&gt; of the book &lt;a href=&quot;https://java.by-comparison.com/&quot;&gt;Java by Comparison&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both the &lt;a href=&quot;https://martinfowler.com/eaaCatalog/specialCase.html&quot;&gt;Special Case pattern&lt;/a&gt; , (applying &lt;a href=&quot;https://martinfowler.com/bliki/TellDontAsk.html&quot;&gt;Tell, don’t ask&lt;/a&gt;), or using the option type functionally (applying &lt;a href=&quot;https://talesfrom.dev/blog/map-dont-ask&quot;&gt;Map, don’t ask&lt;/a&gt;) avoid the smelly conditionals.&lt;/p&gt;

&lt;p&gt;We think that, in this case, using the &lt;a href=&quot;https://martinfowler.com/eaaCatalog/specialCase.html&quot;&gt;Special Case pattern&lt;/a&gt; is clearer, although the solution is arguably less general than using an option type functionally.&lt;/p&gt;

</description>
          <pubDate>2025-12-13T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/12/simple-temporary-field-example</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/12/simple-temporary-field-example</guid>
        </item>
      
    
      
        <item>
          <title>Parallel change example: simplifying some test builders</title>
          <description>&lt;h1 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h1&gt;

&lt;p&gt;In this post we’ll revisit the design of a test builder using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;Curiously recurring template pattern (CRT)&lt;/a&gt;, that we showed in a previous post: &lt;a href=&quot;https://codesai.com/posts/2025/07/segregating-test-builder&quot;&gt;Segregating a test builder applying the curiously recurring template pattern&lt;/a&gt;, and discuss how we simplified it using composition after gaining some insights about the domain of our application.&lt;/p&gt;

&lt;p&gt;We’ll also describe how we applied a &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; to incrementally refactor from the design using generics to the new design using composition without breaking the tests in any moment&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;2-the-initial-design&quot;&gt;2. The initial design.&lt;/h1&gt;

&lt;p&gt;We applied the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;CRT pattern&lt;/a&gt; to design three test builders that shared most of their setters. The design enabled chaining setter methods in any order while restricting available methods to only those relevant for building each specific claim type.&lt;/p&gt;

&lt;p&gt;This is the code of the base test builder using generics and the &lt;em&gt;CRT pattern&lt;/em&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/eb6e5ed25ccdea2421565b6981ca488e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And these are the three concrete derived test builders&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a7b3ca583040547457e510397b9d150e.js&quot;&gt;&lt;/script&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaimBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/396bb57f884025dabeec6c72a1ecbec2.js&quot;&gt;&lt;/script&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaimBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3cf143e672aed604aefa083034c94541.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This design solved the problems we faced because it enabled chaining setter methods in any order while restricting available methods to only those relevant for building each specific claim type.&lt;/p&gt;

&lt;h1 id=&quot;3-domain-insights-set-our-minds-free&quot;&gt;3. Domain insights set our minds free.&lt;/h1&gt;

&lt;p&gt;We had two implementations of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;, that were modelling the two different states of a claim in our process, and a &lt;a href=&quot;https://martinfowler.com/eaaCatalog/dataTransferObject.html&quot;&gt;Data Transfer Object (DTO)&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt;. They shared most of their data and that’s why we were trying to build them using common code. Still, something was off 🤔.&lt;/p&gt;

&lt;p&gt;Later, we learned that we were not modelling our domain usefully. Thinking about the behaviour of our application we realized that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt; were not actually representing possible states of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt;. Instead, they represented steps in the workflow of making a claim. We had conflated concepts.&lt;/p&gt;

&lt;p&gt;To encode this learning, we started by renaming the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; interface and its two implementations, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;, to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimCommand&lt;/code&gt;,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt;, respectively. Then we renamed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; since that name was not taken anymore.&lt;/p&gt;

&lt;p&gt;Then, it was easier to see that it made no sense to use inheritance in the test data builders. The design using the &lt;em&gt;CRT pattern&lt;/em&gt; was solving the symptoms caused by having conflated the concepts of the claim state and the steps in a claim opening workflow, but not the actual problem. This realization led us to separate those concepts which then enabled a simpler design option for the test builders: &lt;strong&gt;composition&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;4-applying-parallel-change-to-move-from-inheritance-to-composition&quot;&gt;4. Applying parallel change to move from inheritance to composition.&lt;/h1&gt;

&lt;p&gt;We applied &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; to incrementally introduce the new composition-based design through refactoring without making the tests fail at any moment.&lt;/p&gt;

&lt;p&gt;We divided this introduction of the new design in two steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Introducing new composition based test builders and removing the inheritance, generic based ones for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Introducing a new test builder for&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; that does not derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s comment each step in more detail:&lt;/p&gt;

&lt;h2 id=&quot;4-1-introducing-new-composition-based-test-builders-and-removing-the-inheritance-generic-based-ones-for-openclaimcommand-and-notifyopenedclaimcommand&quot;&gt;4. 1. Introducing new composition based test builders and removing the inheritance, generic based ones for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt;.&lt;/h2&gt;

&lt;p&gt;We’ll apply two &lt;strong&gt;parallel changes&lt;/strong&gt;, one for each of the new composition based test builders.&lt;/p&gt;

&lt;h3 id=&quot;4-1-1-parallel-change-to-introduce-the-new-openclaimcommand-test-builder&quot;&gt;4. 1. 1. Parallel change to introduce the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; test builder.&lt;/h3&gt;

&lt;h4 id=&quot;4-1-1-1-expansion&quot;&gt;4. 1. 1. 1. Expansion.&lt;/h4&gt;

&lt;p&gt;We generated a builder for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; using AI, renamed its setters to our liking, and used builder composition to improve readability&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; (check the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of&lt;/code&gt; method in the code below). This is the resulting builder:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/88ce9749e16444c895e5b4cb56a4055d.js&quot;&gt;&lt;/script&gt;

&lt;h4 id=&quot;4-1-1-2-migration&quot;&gt;4. 1. 1. 2. Migration.&lt;/h4&gt;

&lt;p&gt;We changed the places where the old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaimBuilder&lt;/code&gt; was used to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenCommandBuilder&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;As an example, this is a fragment of a test case before being migrated:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8a46283ccda5b5762863d58cc1a73fac.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and after being migrated:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ceb6d8010c29cbe6ab826778da6a5737.js&quot;&gt;&lt;/script&gt;

&lt;h4 id=&quot;4-1-1-3-contraction&quot;&gt;4. 1. 1. 3. Contraction.&lt;/h4&gt;

&lt;p&gt;Finally, we removed the imports of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyForOpeningBuilder&lt;/code&gt;, and deleted the class.&lt;/p&gt;

&lt;h3 id=&quot;4-1-2-parallel-change-to-introduce-the-new-notifyopenedclaimcommand-test-builder&quot;&gt;4. 1. 2. Parallel change to introduce the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt; test builder.&lt;/h3&gt;

&lt;h4 id=&quot;4-1-2-1-expansion&quot;&gt;4. 1. 2. 1. Expansion.&lt;/h4&gt;

&lt;p&gt;We generated a builder for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt; using AI, renamed its setters to our liking, and used builder composition to improve readability. This is the resulting builder:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7a86f0b0c19efff00f277e9a2ad0ed63.js&quot;&gt;&lt;/script&gt;

&lt;h5 id=&quot;4-1-2-2-migration&quot;&gt;4. 1. 2. 2. Migration.&lt;/h5&gt;

&lt;p&gt;We changed the places where the old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaimBuilder&lt;/code&gt; was used to use&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommandBuilder&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;As an example, this is a fragment of a test case before being migrated:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ceb6d8010c29cbe6ab826778da6a5737.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and after being migrated:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a168897ceb8d8f49bd6695b774882143.js&quot;&gt;&lt;/script&gt;

&lt;h4 id=&quot;4-1-2-3-contraction&quot;&gt;4. 1. 2. 3. Contraction.&lt;/h4&gt;

&lt;p&gt;Finally, we removed the imports of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaimBuilder&lt;/code&gt;, and deleted the class.&lt;/p&gt;

&lt;h2 id=&quot;4-2-introducing-a-new-test-builder-forclaim-that-does-not-derive-from-claimbuilder&quot;&gt;4. 2. Introducing a new test builder for&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; that does not derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt;.&lt;/h2&gt;

&lt;h2 id=&quot;4-2-1-expansion&quot;&gt;4. 2. 1. Expansion.&lt;/h2&gt;

&lt;p&gt;We started by creating a new test builder for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilderX&lt;/code&gt; that did not derive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt; but had the same setter methods:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5f97370b6a4f4cb74249ca95252ea748.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then, we overloaded the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of&lt;/code&gt; method of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommandBuilder&lt;/code&gt;. The new version of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of&lt;/code&gt; method received a  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilderX&lt;/code&gt;. We did the same for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of&lt;/code&gt; method of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommandBuilder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also modified the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; method of both classes, so that, if the field &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claimBuilderX&lt;/code&gt; was not null, we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilderX&lt;/code&gt; to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt;, whereas if it was, we used the old test data builder, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt;. This conditional code was a scaffolding that allowed us to incrementally migrate from the old design to the new design.&lt;/p&gt;

&lt;p&gt;This is the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommandBuilder&lt;/code&gt; with some code omitted for the sake of brevity:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/15830619891cee3880cfb15d68338641.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommandBuilder&lt;/code&gt; with some code omitted for the sake of brevity:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/487a673c04d69bef80d7df12d1422707.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The last part of the expansion was importing statically the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aClaim&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilderX&lt;/code&gt; in all the tests in which the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aClaimDto&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; is used. I did it with &lt;a href=&quot;https://github.com/trikitrok/vibe-code-experiments/tree/main/tools/add-import-in-java&quot;&gt;a script&lt;/a&gt; that I had vibe coded with &lt;a href=&quot;https://www.jetbrains.com/junie/&quot;&gt;Junie&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;4-2-2-migration&quot;&gt;4. 2. 2. Migration.&lt;/h2&gt;

&lt;p&gt;After all the scaffolding we prepared in the expansion phase, the migration consisted only in substituting the text &lt;em&gt;“aClaimDto”&lt;/em&gt; with &lt;em&gt;“aClaim”&lt;/em&gt; in every test case in which the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aClaimDto&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; was being used.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/simplifying_builders/replace_in_files.png&quot; alt=&quot;Replacing text in files.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Replacing text in files.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;After executing this text substitution all the tests kept passing.&lt;/p&gt;

&lt;h2 id=&quot;4-2-3-contraction&quot;&gt;4. 2. 3. Contraction.&lt;/h2&gt;

&lt;p&gt;First, we removed the static imports of the unused &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aClaimDto&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; using IntelliJ’s &lt;a href=&quot;https://www.jetbrains.com/guide/tips/optimize-imports/&quot;&gt;Optimize imports command&lt;/a&gt; on all the tests.&lt;/p&gt;

&lt;p&gt;After that, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; class was being used only in the scaffolding we added in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommandBuilder&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommandBuilder&lt;/code&gt; during the expansion phase to make the migration possible.&lt;/p&gt;

&lt;p&gt;We removed the methods that the IDE marked as unused and ran the &lt;a href=&quot;https://www.jetbrains.com/guide/tips/optimize-imports/&quot;&gt;Optimize imports command&lt;/a&gt; in both tests. After that, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; became dead code and we deleted it.&lt;/p&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt; was the only remaining class inheriting from the generic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt; class using generics, after deleting it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt; also became dead code, and we could delete it as well.&lt;/p&gt;

&lt;p&gt;Finally, we renamed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilderX&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt; since that name was not taken anymore.&lt;/p&gt;

&lt;h1 id=&quot;5-final-design&quot;&gt;5. Final design.&lt;/h1&gt;

&lt;p&gt;The new design of the test builders using composition is easier to understand and maintain than the previous one using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;CRT pattern&lt;/a&gt; because the new design does not use generics nor inheritance.&lt;/p&gt;

&lt;h1 id=&quot;6-summary&quot;&gt;6. Summary.&lt;/h1&gt;

&lt;p&gt;After realizing that we were conflating concepts: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt; were not states of a claim but steps in a workflow, we clarified the domain model renaming them to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenClaimCommand&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyOpenedClaimCommand&lt;/code&gt;, respectively, and also renaming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This domain insight also removed the need for inheritance in the test builders using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;CRT pattern&lt;/a&gt;, and opened the door to a simpler design: composition-based test builders, that better matched the domain.&lt;/p&gt;

&lt;p&gt;We applied a &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; to safely move from one design to the other without ever breaking the test suite. In the expansion phase we generated new builders and introduced temporary scaffolding, then, in the migration phase, we gradually migrated the test builders usage in the tests, and only once everything was migrated, we finally performed a controlled cleanup of the old classes.&lt;/p&gt;

&lt;p&gt;The final design avoids generics and inheritance entirely, relying instead on straightforward composition. Each command builder now composes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimBuilder&lt;/code&gt;, leading to a clearer, flatter structure. This makes the builders easier to understand, modify, and extend while better reflecting the clarified domain model.&lt;/p&gt;

&lt;p&gt;We encourage you to learn more about &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; so you too can join &lt;a href=&quot;https://www.infoq.com/presentations/The-Limited-Red-Society/&quot;&gt;The Limited Red Society&lt;/a&gt; and practice safer, incremental refactoring&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank my colleague &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about this post.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.linkedin.com/in/carlosmiguelseco/&quot;&gt;Carlos Miguel Seco&lt;/a&gt; for giving us the opportunity to work with him on a very interesting project.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/@cottonbro/collections/&quot;&gt;cottonbro studio&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See the fantastic &lt;a href=&quot;https://www.infoq.com/presentations/The-Limited-Red-Society/&quot;&gt;The Limited Red Society&lt;/a&gt; talk to know more about the origins of this technique.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Read Nat Pryce’s short post about composing test data builders: &lt;a href=&quot;http://www.natpryce.com/articles/000726.html&quot;&gt;Tricks with Test Data Builders: Combining Builders&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Our training &lt;a href=&quot;https://codesai.com/cursos/refactoring/&quot;&gt;Code Smells &amp;amp; Refactoring&lt;/a&gt; makes a special emphasis on teaching and practising the &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; technique so teams can refactor safely and incrementally without breaking their codebase.&lt;/p&gt;

</description>
          <pubDate>2025-11-30T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/11/simplifying-builders-parallel-change</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/11/simplifying-builders-parallel-change</guid>
        </item>
      
    
      
        <item>
          <title>Refactoring the tests after a &quot;Breaking Out&quot; (peer detection techniques)</title>
          <description>&lt;h1 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h1&gt;

&lt;p&gt;This post is a continuation of our &lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;previous post devoted to the &lt;strong&gt;breaking out&lt;/strong&gt; technique&lt;/a&gt;, in which we explained the &lt;strong&gt;breaking out&lt;/strong&gt; technique which consists in splitting a large object into a group of collaborating objects and/or values.&lt;/p&gt;

&lt;p&gt;This technique is useful to fix cohesion problems caused by delaying design decisions until we learn more about the domain when facing volatile and poorly understood domains.&lt;/p&gt;

&lt;p&gt;We also described how to use code smells and, in more severe cases, testability problems as indicators of poor cohesion to recognize when we need the technique, and how to apply it.&lt;/p&gt;

&lt;p&gt;Finally, we highlighted two facts about the code after applying a &lt;strong&gt;breaking out&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The new objects created through this refactoring are treated as
  &lt;em&gt;internals&lt;/em&gt; rather than &lt;em&gt;peers&lt;/em&gt;.&lt;/li&gt;

&lt;li&gt;The tests still have poor
  &lt;a href=&quot;https://www.youtube.com/watch?v=bDaFPACTjj8&quot;&gt;readability&lt;/a&gt;,
  &lt;a href=&quot;https://www.youtube.com/watch?v=CAttTEUE9HM&quot;&gt;writability&lt;/a&gt;,
  &lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;specificity&lt;/a&gt;
  and
  &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt;,
  but high
  &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the end of the &lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;previous post&lt;/a&gt;, there were to open questions that we’ll try to answer in this post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Should we refactor the tests now or later?&lt;/li&gt;
&lt;li&gt;How do we refactor the tests?&lt;/li&gt;
&lt;li&gt;How do we decide if we should promote an internal object to be a peer?&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;2-refactoring-the-tests-now-or-later&quot;&gt;2. Refactoring the tests now or later?&lt;/h1&gt;

&lt;h2 id=&quot;2-1-context&quot;&gt;2. 1. Context.&lt;/h2&gt;

&lt;p&gt;The following figure summarizes the &lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion#what_about_the_tests&quot;&gt;analysis of some test properties of the original tests we did in our previous post&lt;/a&gt;:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/original_tests_properties_no_values_with_labels.png&quot; alt=&quot;Original tests properties.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Original tests properties.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This analysis of test properties will help us identify the trade-offs involved in deciding whether to refactor the tests now or defer it to a more advantageous time.&lt;/p&gt;

&lt;p&gt;Another information we need to consider to make the decision is &lt;em&gt;how we got to this situation&lt;/em&gt;. Let’s do a quick recap:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We were starting a new area of code, and test-drove the behaviour through the public interface of an object without attempting to impose much structure, in order to have more time to learn before committing to any design decision.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;After observing some code smells (and possibly some test smells) produced by a lack of cohesion, we decided to break up the original object into smaller components. After that refactoring, the resulting composite object (original object + extracted internals and values) has better cohesion, but the original tests have not changed.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We also need to know that the refactoring of the test comprises two steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Testing “problematic” internals and values independently, (where “problematic” means that they cause painful testability problems).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Refactoring the original tests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s analyze the first step.&lt;/p&gt;

&lt;h2 id=&quot;2-2-testing-problematic-types-independently-now-or-later&quot;&gt;2. 2. Testing “problematic” types independently now or later?&lt;/h2&gt;

&lt;h3 id=&quot;2-2-1-consequences-of-testing-problematic-types-independently&quot;&gt;2. 2. 1. Consequences of testing “problematic” types independently.&lt;/h3&gt;

&lt;p&gt;Let’s start by thinking what testing an internal object or value independently means in terms of &lt;a href=&quot;https://www.youtube.com/watch?v=bDaFPACTjj8&quot;&gt;readability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=CAttTEUE9HM&quot;&gt;writability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;specificity&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improvements in readability and writability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The new tests would be more granular and focused because they are testing only one behaviour. This will make them easier to write and understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improvement in specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With these new tests, it would be much easier to interpret test failures (including failures in the original tests).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improvement in composability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can separately test each different behaviour (dimension of variability) through its interface. Then adding a few test cases that verify the combination of behaviours will allow the number of test cases to grow additively instead of multiplicatively, while still providing confidence that the tests are sufficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced structure-insensitivity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The new tests are coupled to the interfaces of the new types. Since the original tests were not aware of these interfaces, this added coupling increases the cost of any refactoring that changes one of the new interfaces.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/focused_properties_no_values_with_labels.png&quot; alt=&quot;Test properties when testing “problematic” internals and values independently.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Test properties when testing “problematic” internals and values independently.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Therefore, independently testing internals or values through their interfaces can ease most of the testability problems of the original tests. However, this comes at the cost of tighter coupling between the tests and the production code.&lt;/p&gt;

&lt;h3 id=&quot;2-2-2-trade-off-and-contexts&quot;&gt;2. 2. 2. Trade-off and contexts.&lt;/h3&gt;

&lt;p&gt;There’s a trade-off between structure-insensitivity, and other desirable test properties like specificity, composability, readability and writability. There’s no ideal general solution, so we’ll have to “pick our poison” depending on the context.&lt;/p&gt;

&lt;p&gt;In a context in which we don’t have enough knowledge yet about the problem to delimit the object’s boundaries well, it’s likely that we’ll do a lot of refactoring as we learn more about the domain. Some of those refactorings may involve refining the interfaces of the new types we introduced by applying the &lt;strong&gt;breaking out&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a context marked by volatility and limited knowledge, it’s preferable to maintain a high degree of structure-insensitivity to avoid increasing the cost of refactoring while preserving other desirable test properties, ensuring that applying new learnings remains inexpensive. That is precisely why we decided not to impose much structure when we started test-driving the behaviour through the entry point.&lt;/p&gt;

&lt;p&gt;If after the &lt;strong&gt;breaking out&lt;/strong&gt;, we are still in the same context of volatility and lack of knowledge, it might be &lt;strong&gt;wise to defer independently testing the extracted types independently&lt;/strong&gt; and continue relying on the original tests for a while. In this kind of context, testing them independently might be dangerous because it prematurely couples the tests to interfaces that we may later realize were not sound, leading to more expensive refactorings to refine those internal interfaces.&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. Keeping the original tests with low specificity, composability, readability and writability will eventually slow us down and produce maintainability problems, but for a while, having a high structure-insensitivity might pay off by allowing cheaper refactoring of internal interfaces.&lt;/p&gt;

&lt;p&gt;This trade-off pays off well until it doesn’t 🙂. This happens when the pain of poor specificity, readability, composability and/or writability starts weighing more than the benefits of cheap refactoring due to high structure-insensitivity. This tipping point may happen due to different reasons, for instance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. More knowledge and low volatility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We have learned enough about the problem so that the code is more stable and has some degree of structure. Interfaces and abstractions are more stable, and their refactoring becomes less likely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Too much testability pain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The behaviour of some internals becomes so complex that it exacerbates the testability problems so much that they weigh more than the benefits of cheap refactoring of interfaces.&lt;/p&gt;

&lt;h3 id=&quot;2-2-3-consequences-of-deferring-testing-problematic-types-independently&quot;&gt;2. 2. 3. Consequences of deferring testing “problematic” types independently.&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Poor readability and writability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We might somehow palliate the pain by using explanatory helper methods and test patterns such as &lt;a href=&quot;http://www.natpryce.com/articles/000714.html&quot;&gt;test data builder&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/bliki/ObjectMother.html&quot;&gt;object mother&lt;/a&gt;, etc. Keep in mind that these techniques only alleviate the symptoms; they don’t address the root of the problem. Even so, they are very useful for reducing the pain caused by poor readability and writability during the period in which higher structure-insensitivity is advantageous for us.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Poor specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If this problem starts being especially painful, we may need to start testing independently some problematic internal or value. I think there’s no other technique to reduce this kind of pain. Although, we might get lucky and not get regressions that are difficult to interpret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Poor composability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This problem may even make it impossible to defer independently testing a new type that is causing it. As we said before when talking about &lt;a href=&quot;https://tidyfirst.substack.com/p/tdds-missing-skill-behavioral-composition&quot;&gt;behavioural composition&lt;/a&gt;, we won’t be able to test-drive complex behaviours without breaking them into smaller behaviours. In such cases, we would have no other choice but to start test-driving independently the “problematic” internal or value in order to reduce the size of the increments of behaviour we are tackling. We’ll see that this may or may not involve using test doubles.&lt;/p&gt;

&lt;h3 id=&quot;2-2-4-conclusions&quot;&gt;2. 2. 4. Conclusions.&lt;/h3&gt;

&lt;p&gt;To summarize, keep in mind that the strategy of &lt;strong&gt;deferring testing the new types independently&lt;/strong&gt; is beneficial only in a context where we don’t have enough knowledge of the problem because it avoids committing prematurely to any design decision and makes it cheaper to refine the design as we learn.&lt;/p&gt;

&lt;p&gt;Having said that, using this strategy in a different context can be dangerous. The more we defer refactoring the tests, the more expensive it will become and the more pain we’ll suffer test-driving new features (&lt;strong&gt;accruing&lt;/strong&gt; and &lt;strong&gt;recurring&lt;/strong&gt; interests of technical debt at play). So don’t wait too long to refactor the tests.&lt;/p&gt;

&lt;p&gt;There might be contexts in which we have a more stable design, and/or enough knowledge of the domain. In these contexts, even the initial strategy of test-driving without imposing much structure might make little sense because we have better odds that the design we impose proves successful&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. We’ll discuss this deeper when we talk about the &lt;strong&gt;budding off&lt;/strong&gt; technique in a future post.&lt;/p&gt;

&lt;h2 id=&quot;2-3-why-should-we-only-test-problematic-types-independently-and-not-all-types&quot;&gt;2. 3. Why should we only test “problematic” types independently, and not all types?&lt;/h2&gt;

&lt;p&gt;We have shown how independently testing the new types produced by a &lt;strong&gt;breaking out&lt;/strong&gt; through their interfaces can ease most of the testability problems of the original tests. However, these gains come at a price: we lose structure-insensitivity because the tests get coupled to the interfaces of the new types.&lt;/p&gt;

&lt;p&gt;This trade-off is the reason why we should independently test only the “problematic” types, i.e., the ones that produce painful testability problems. This is a sensible limitation. If we tested independently any internal or value that is not problematic, we’d be trading structure-insensitivity for nothing. This mistake would create unnecessary coupling between our tests and the structure of our code, and we’d be much worse off. The only reason we test any of them independently is &lt;strong&gt;to ease testability problems&lt;/strong&gt; that are becoming too painful&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;3-refactoring-the-tests&quot;&gt;3. Refactoring the tests.&lt;/h1&gt;

&lt;p&gt;As we said, this is done in two steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Testing “problematic” internals and values independently.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Refactoring the original tests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s go deeper into each step.&lt;/p&gt;

&lt;h2 id=&quot;3-1-testing-problematic-internals-and-values-independently&quot;&gt;3. 1. Testing “problematic” internals and values independently.&lt;/h2&gt;

&lt;p&gt;We independently test any internal value that is causing painful testability problems. We don’t need to test all of them at once, instead we can do it incrementally as needed. As we saw, these new tests will ease most of the testability problems of the original tests. Once we have them in place, we can simplify the original composite object’s tests to make them easier to maintain.&lt;/p&gt;

&lt;h2 id=&quot;3-2-refactoring-the-original-tests&quot;&gt;3. 2. Refactoring the original tests.&lt;/h2&gt;

&lt;p&gt;Remember that, after applying a &lt;strong&gt;breaking out&lt;/strong&gt; to improve cohesion, all the extracted collaborator objects are treated as internals. Promoting&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; any of those internals to be a peer is a separate, explicit decision we have to take. This means that there are two options to refactor the original composite object’s tests, each with its own advantages and disadvantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not promoting any “problematic” internal to be a peer.&lt;/li&gt;
&lt;li&gt;Promoting “problematic” internals to be peers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;3-2-1-not-promoting-any-problematic-internal-to-be-a-peer&quot;&gt;3. 2. 1. Not promoting any “problematic” internal to be a peer.&lt;/h3&gt;

&lt;h4 id=&quot;3-2-1-1-how-to-do-it&quot;&gt;3. 2. 1. 1. How to do it?&lt;/h4&gt;

&lt;p&gt;If we take this option, what we can do to simplify the original composite object’s tests would be to &lt;strong&gt;remove most of the test cases addressing behaviours that are now being independently tested through closer, more appropriate interfaces&lt;/strong&gt;. We are taking advantage of the improvement in &lt;strong&gt;composability&lt;/strong&gt; that the tests through more appropriate interfaces provide.&lt;/p&gt;

&lt;p&gt;Let’s see how doing this improves different testability problems.&lt;/p&gt;

&lt;h4 id=&quot;3-2-1-2-consequences&quot;&gt;3. 2. 1. 2. Consequences.&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Writability and readability problems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The size of the composite object’s tests is reduced, which makes them less unfocused 🚀. In a way, the pain caused by poor &lt;strong&gt;writability&lt;/strong&gt; and &lt;strong&gt;readability&lt;/strong&gt; is still there, but we don’t feel it so much because there are fewer test cases through the interface of the composite object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specificity problems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These problems were already addressed by testing problematic types independently. We’ll still find tests that are checking the same behaviour from different interfaces, only that there are fewer because we have deleted some composite object’s tests. This overlap still causes that a regression can make several tests fail, however, it’s easier to diagnose the origin of the failures: if some composite object’s test cases and some more focused test cases fail, the problem is likely located in an internal or a value, whereas, if only the composite object’s tests fail, the problem is likely located in the composite object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Composability problems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Choosing not to promote any internal to be a peer when simplifying the composite object’s tests does not improve composability any further than what testing a problematic internal independently does. However, it forces a way of doing TDD when faced with hard composability problems: when we are not able to test-drive an object because we can’t find a way to decompose its behaviour in small increments, we go one level of abstraction down, test-drive an internal type with a smaller behaviour, and then use that inner behaviour as a stepping stone to test-drive the original behaviour more easily (this is what we would do in the classical style of TDD). Working this way is inside-out in nature, and, as such, is less &lt;a href=&quot;https://martinfowler.com/bliki/Yagni.html&quot;&gt;YAGNI&lt;/a&gt; friendly than test-driving outside-in. To palliate this problem, we should be careful to only test-drive the internal behaviour that we need to make test-driving the whole behaviour possible, and no more.&lt;/p&gt;

&lt;h4 id=&quot;3-2-1-3-some-observations&quot;&gt;3. 2. 1. 3. Some observations.&lt;/h4&gt;

&lt;p&gt;Finally, we’d like to add two observations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choosing not to promote any internal to be a peer when simplifying the composite object’s tests does not lower any further the &lt;em&gt;structure-insensitivity&lt;/em&gt;. The &lt;em&gt;loss of structure-insensitivity&lt;/em&gt; was already caused by independently testing problematic internals through their interfaces.
&lt;/li&gt;
&lt;li&gt;If &lt;em&gt;specificity&lt;/em&gt; and/or &lt;em&gt;composability&lt;/em&gt; problems are very painful, we may be better off promoting the internals causing the pain to be peers. However, if those problems aren’t so painful and we are still worried about &lt;em&gt;structure-insensitivity&lt;/em&gt;, not doing it might be tolerable, because, as we’ll see in the next session, promoting them introduces a little more coupling.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;3-2-2-promoting-some-problematic-internals-to-be-peers&quot;&gt;3. 2. 2. Promoting some “problematic” internals to be peers.&lt;/h3&gt;

&lt;h4 id=&quot;3-2-2-1-how-to-do-it&quot;&gt;3. 2. 2. 1. How to do it?&lt;/h4&gt;

&lt;p&gt;Let’s start by discussing what it takes to promote an internal to be a peer of the composite object:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Invert the dependency. This may involve refining the interface of the internal and, in the case of statically typed languages, extracting an interface.&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;Simulate the peer’s behaviour with test doubles in the composite object’s tests.
&lt;/li&gt;
&lt;li&gt;Inject the peer (previously an internal) into the composite object.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;3-2-2-2-when-should-we-do-it&quot;&gt;3. 2. 2. 2. When should we do it?&lt;/h4&gt;

&lt;p&gt;In our opinion, we should promote any internal that clearly matches a peer stereotype&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. They were already dependencies, strategies or notifications from the outset, but we decided to include their behaviour in the scope of our original tests because we weren’t sure about their interfaces. Now that we have learned more, promoting them to peers will greatly improve testability.&lt;/p&gt;

&lt;p&gt;In the case of internals that don’t clearly match any peer stereotype, we should promote them to peers only if being a peer provides substantial testability benefits. In this case, we would be treating an actual internal into a peer, which means coupling to an internal detail, so we better be gaining significant improvements in &lt;em&gt;readability&lt;/em&gt;, &lt;em&gt;writability&lt;/em&gt;, &lt;em&gt;specificity&lt;/em&gt; or &lt;em&gt;composability&lt;/em&gt; to compensate for the loss in structure-insensitivity. The rich and complex behaviour of these internals is what leads to substantial testability benefits when they are promoted to peers, even though they don’t correspond to any of the object peer stereotypes. We argue that they belong to what Fowler calls “objects with interesting behaviour”&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;3-2-2-3-consequences&quot;&gt;3. 2. 2. 3. Consequences.&lt;/h4&gt;

&lt;p&gt;Let’s see how choosing this option affects the test properties we have been discussing throughout the post:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writability&lt;/strong&gt; and &lt;strong&gt;readability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On one hand, tests of the composite object that use test doubles verify only the composite’s own behavior, making them shorter and more focused. They also document the communication protocols between the composite object and its peers&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, the more focused tests written through the interfaces of the peers will check only their behaviour and document how they fulfill their roles (contracts).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is much better with this option. Now, a failure can affect only either the composite object’s tests or a peer’s tests, so it’s straightforward to know where the problem is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Composability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is addressed by simulating the behaviour of the peers (their roles) with test doubles while test-driving the behaviour of the composite object. Afterwards, we test-drive the implementation of the roles to verify that they behave according to their roles.&lt;/p&gt;

&lt;p&gt;In the tests of the composite object we describe what we expect of the peer, the contract (or role) between the composite object and its peer, whereas in the tests of the peer we verify that it indeed fulfills that contract.&lt;/p&gt;

&lt;p&gt;This is more outside-in and more YAGNI friendly than the approach required in the previous option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structure-insensitivity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, both the tests of the peer and the composite object are coupled to the peer’s interface. The tests as a whole see the same set of interfaces as in the previous option, but the number of tests coupled to the peer’s interface increases. Therefore, this option increases the coupling between the tests and the production code. This higher degree of coupling might be attenuated using fakes or using hand-made spies and stubs, but we think this may introduce other maintainability problems on its own&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;4-conclusions&quot;&gt;4. Conclusions.&lt;/h2&gt;

&lt;p&gt;In this post, we addressed the questions we raised in our &lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;previous post devoted to the &lt;strong&gt;breaking out&lt;/strong&gt; technique&lt;/a&gt;:&lt;/p&gt;

&lt;h3 id=&quot;question-1-should-we-refactor-the-tests-now-or-later&quot;&gt;Question 1: Should we refactor the tests now or later?&lt;/h3&gt;

&lt;p&gt;After Applying a &lt;strong&gt;Breaking Out&lt;/strong&gt; refactoring, the original tests still have poor readability, writability, specificity, and composability. Despite these disadvantages, such tests have high structure-insensitivity, meaning they are resilient to internal refactorings. We discussed the trade-off between keeping this structure-insensitivity and improving other properties. Testing the new internal types independently can ease many testability issues, but it also couples the tests to specific interfaces, making their refactoring more costly.&lt;/p&gt;

&lt;p&gt;From that trade-off, we derived a key insight: the decision to refactor tests immediately or defer it depends on context. In volatile or poorly understood domains, deferring independent testing of the new types preserves flexibility and reduces refactoring costs, even if it temporarily worsens test quality. As our understanding of the domain grows and the design stabilizes or the testability pains grow, it becomes beneficial to refactor the tests.&lt;/p&gt;

&lt;h3 id=&quot;question-2-how-do-we-refactor-the-tests&quot;&gt;Question 2: How do we refactor the tests?&lt;/h3&gt;

&lt;p&gt;This refactoring is done in two steps: first, we test “problematic” types independently, and then we simplify the original tests. Testing “problematic” types independently improves the readability, writability, specificity, and composability of the tests, though at the cost of greater coupling with the production code. Therefore, we should only test independently those internals or values that cause clear testability pain, thus avoiding introducing coupling for little benefit.&lt;/p&gt;

&lt;p&gt;There are two ways to simplify the original composite object’s tests, depending on whether we decide to promote some problematic internals to peers or not. If we decide not to do it, we simplify the composite object’s tests by deleting some test cases; if we decide to do it, we simplify them by introducing test doubles. The first option doesn’t add much improvement over testing “problematic” types independently, but still reduces the degree of pain by having fewer test cases. Promoting “problematic” internals to peers enhances the desirable properties of tests even more, but introduces greater coupling, since the composite object’s tests also become coupled to the new interfaces.&lt;/p&gt;

&lt;h3 id=&quot;question-3-how-do-we-decide-if-we-should-promote-an-internal-object-to-be-a-peer&quot;&gt;Question 3: How do we decide if we should promote an internal object to be a peer?&lt;/h3&gt;

&lt;p&gt;We argued that all internals that match peer stereotypes should be promoted to peers to gain testability benefits. Seeing the decision of promoting an internal to a peer as a bet, promoting one that clearly matches a peer stereotype is a bet with good odds. In contrast, promoting a “problematic” internal that doesn’t match any peer stereotype has worse odds, so, to avoid increasing coupling for little or no gain, we need to be very confident that its promotion will provide clear testability benefits before doing it. We discussed what to assess to make a better decision. We also noted that evaluating these odds depends on both experience and the stability of the design.&lt;/p&gt;

&lt;h3 id=&quot;final-words&quot;&gt;Final words.&lt;/h3&gt;

&lt;p&gt;In summary, the key takeaway is that we have many options, and by identifying the trade-offs between different testability properties, we can judge them according to context and the maturity of the design. Balancing cohesion, testability, and flexibility is not a one-time decision but an evolving process.&lt;/p&gt;

&lt;p&gt;Thanks for coming to the end of this post. We hope that what we explain here will be useful to you.&lt;/p&gt;
&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;
&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;5-acknowledgements&quot;&gt;5. Acknowledgements.&lt;/h2&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@ali-soheil-2154370577/&quot;&gt;Ali Soheil&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;6-references&quot;&gt;6. References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/35957157-thinking-in-bets&quot;&gt;Thinking in Bets: Making Smarter Decisions When You Don’t Have All the Facts&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Annie_Duke&quot;&gt;Anne Duke&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20090807004827/http://msdn.microsoft.com/en-ca/magazine/dd882516.aspx&quot;&gt;Test-Driven Design Using Mocks And Tests To Design Role-Based Objects &lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/%F0%9F%92%BBisaiah-perumalla-8537563/&quot;&gt;Isaiah Perumalla&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;,  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;Test Desiderata 2/12 Tests Should be Structure-Insensitive&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;7-notes&quot;&gt;7. Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] An extreme case of poor structure-insensitivity happens when we fall in the dangerous &lt;strong&gt;class-as-unit trap&lt;/strong&gt;. Never go there, it’s a scenario full of pain.&lt;/p&gt;

&lt;p&gt;Read &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, if you are using the London school style of TDD (or mockist TDD).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Design decisions are always a bet against the future evolution of a system.&lt;/p&gt;

&lt;p&gt;When we are assessing the quality of a decision, it’s important that we don’t take into account its result, which is a very common cognitive bias called &lt;a href=&quot;https://www.theuncertaintyproject.org/tools/fielding-outcomes&quot;&gt;“fielding outcomes”&lt;/a&gt; that impairs our learning loops.&lt;/p&gt;

&lt;p&gt;So, we should assess a decision thinking if it had good odds to be successful given what we knew at the moment we took it, independently of its result.&lt;/p&gt;

&lt;p&gt;You can read more about improving decision making in an uncertain world in &lt;a href=&quot;https://en.wikipedia.org/wiki/Annie_Duke&quot;&gt;Anne Duke&lt;/a&gt;’s wonderful &lt;a href=&quot;https://www.goodreads.com/book/show/35957157-thinking-in-bets&quot;&gt;Thinking in Bets: Making Smarter Decisions When You Don’t Have All the Facts&lt;/a&gt; book.&lt;/p&gt;

&lt;p&gt;This interview, &lt;a href=&quot;https://www.youtube.com/watch?v=p8HAJh52DaE&quot;&gt;Thinking in Bets for Engineers&lt;/a&gt;, is very interesting as well.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3]  We consider that thinking about testability benefits to decide whether to independently test new types introduced through refactoring or not is useful in the context of a &lt;strong&gt;breaking out&lt;/strong&gt;. There could be other valid reasons to write those new tests. You can read the following two posts to go deeper into this topic:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://tidyfirst.substack.com/p/additional-testing-after-refactoring&quot;&gt;Additional Testing After Refactoring&lt;/a&gt;, Kent Beck&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://xp123.com/revise-tests-while-refactoring-it-depends/&quot;&gt;Revise Tests While Refactoring? It Depends&lt;/a&gt;, Bill Wake&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://xp123.com/the-impact-of-refactoring-on-tests/&quot;&gt;The Impact of Refactoring on Tests&lt;/a&gt;, Bill Wake&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] “Promoting” is a refactoring that makes the role of an internal of an object seen by the rest of the system and the object’s tests. This means that it is treated as a peer of the object. The inverse refactoring of promoting is &lt;a href=&quot;https://emmanuelvalverderamos.substack.com/p/materialization-turning-a-false-peer&quot;&gt;materializing&lt;/a&gt; which “demotes” a peer of an object to be an internal.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] We’d like to note some things about this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- In statically typed languages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We need to extract an interface because we have two implementations: one in the test context and another one in the production context. We shouldn’t simulate a concrete class with test doubles, even if the tool we use allows it. Simulating a concrete class leaves the relationship between the objects implicit. Read &lt;a href=&quot;https://web.archive.org/web/20090418014252/http://mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html&quot;&gt;Test Smell: Mocking concrete classes&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;The meaning of “extracting an interface” depends on whether the language has an interface construct or not: for instance, we would extract an interface in Java or C#, but extract a class whose methods are all pure virtual functions in C++ (at least in the version I used to use).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- In dynamically typed languages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We don’t need to extract an interface to invert the dependency.&lt;/p&gt;

&lt;p&gt;In both cases we should work to avoid the peer’s API from leaking any implementation detail.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] For the GOOS authors the communication patterns between objects are more important than the class structure, (see section &lt;em&gt;Communication over Classification&lt;/em&gt; in chapter 7: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] We commented how using test doubles in an object’s tests to simulate a collaborator that clearly matches a peer stereotype provides substantial testability benefits in our previous post &lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the behaviour of the object is very simple (cyclomatic complexity = 1), we may get by with a broad integration test.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] It appears in the section &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html#ClassicalAndMockistTesting&quot;&gt;Classical and Mockist Testing&lt;/a&gt; of his post &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[…] always use a mock for any object with interesting behavior”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] We plan to treat this topic in a future post.&lt;/p&gt;

</description>
          <pubDate>2025-11-10T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/11/breaking-out-refactoring-the-tests</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/11/breaking-out-refactoring-the-tests</guid>
        </item>
      
    
      
        <item>
          <title>Breaking out to improve cohesion (peer detection techniques)</title>
          <description>&lt;h1 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h1&gt;

&lt;p&gt;In previous posts&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; we talked about the importance of distinguishing an object’s peers from its internals in order to write maintainable unit tests, and how the &lt;strong&gt;peer-stereotypes&lt;/strong&gt; help us detect an object’s peers.&lt;/p&gt;

&lt;p&gt;When we use the term &lt;strong&gt;object&lt;/strong&gt; in this post, we are using the meaning from &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software, Guided by Tests (GOOS)&lt;/a&gt; book:&lt;/p&gt;

&lt;p&gt;Objects “have an identity, might change state over time, and model computational processes”. They should be distinguished from values which “model unchanging quantities or measurements”  (&lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;value objects&lt;/a&gt;). An object can be an &lt;strong&gt;internal&lt;/strong&gt; or a &lt;strong&gt;peer&lt;/strong&gt; of another object.&lt;/p&gt;

&lt;p&gt;This post presents three effective techniques for discovering values and object types, &lt;strong&gt;breaking out&lt;/strong&gt;, &lt;strong&gt;budding off&lt;/strong&gt; and &lt;strong&gt;bundling up&lt;/strong&gt;; and then, goes deep into one of them: &lt;strong&gt;breaking out&lt;/strong&gt;. We’ll cover the other two techniques in future posts.&lt;/p&gt;

&lt;h1 id=&quot;2-techniques-to-detect-object-and-value-types&quot;&gt;2. Techniques to detect object and value types.&lt;/h1&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;GOOS&lt;/a&gt; book describes three techniques for discovering object types&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;, some of which might be peers:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Breaking out&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bundling up&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Budding off&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These techniques identify recurring scenarios that indicate when introducing a new object improves a design.&lt;/p&gt;

&lt;p&gt;We rely on both our ability to detect code smells, and on “listening to our tests” (using testability feedback to guide our design) to know when to apply a &lt;strong&gt;breaking out&lt;/strong&gt;. The new object types are introduced through refactoring.&lt;/p&gt;

&lt;p&gt;In the case of &lt;strong&gt;bundling up&lt;/strong&gt;, we rely on “listening to our tests” to detect the need to apply it. Again the new object types are introduced through refactoring.&lt;/p&gt;

&lt;p&gt;In contrast, we detect the need of applying a &lt;strong&gt;budding off&lt;/strong&gt; by recognizing possible cohesion problems while writing a new failing test to drive new behaviour. In this technique we introduce the new object type from the test to prevent cohesion problems. Domain knowledge and previous experience are crucial to apply this technique well.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/object-detection-techniques-goos_transparent.png&quot; alt=&quot;How we detect the need and the mechanism used to apply each of the techniques.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;How we detect the need and the mechanism used to apply each of the techniques&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;GOOS also describes three techniques for discovering value types that share the same names: &lt;strong&gt;breaking out&lt;/strong&gt;, &lt;strong&gt;bundling up&lt;/strong&gt;, and &lt;strong&gt;budding off&lt;/strong&gt;. The mechanisms to introduce new values are similar to the ones described above for object types.&lt;/p&gt;

&lt;p&gt;For values, &lt;strong&gt;bundling up&lt;/strong&gt; is used to eliminate existing &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=10&quot;&gt;data clumps&lt;/a&gt; through refactoring, whereas &lt;strong&gt;budding off&lt;/strong&gt; introduces new values from the outset to prevent &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=11&quot;&gt;primitive obsession&lt;/a&gt; or &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=10&quot;&gt;data clumps&lt;/a&gt;. &lt;strong&gt;Breaking out&lt;/strong&gt; introduces new values by refactoring to improve cohesion.&lt;/p&gt;

&lt;p&gt;In this post we focus on the &lt;strong&gt;breaking out&lt;/strong&gt; technique.&lt;/p&gt;

&lt;h1 id=&quot;3-breaking-out&quot;&gt;3. &lt;strong&gt;Breaking out&lt;/strong&gt;.&lt;/h1&gt;

&lt;p&gt;According to the GOOS authors, this technique consists in splitting a large object into a group of collaborating objects and/or values&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.
Let’s first describe the context in which we apply it.&lt;/p&gt;

&lt;h2 id=&quot;3-1-context&quot;&gt;3. 1. Context.&lt;/h2&gt;

&lt;p&gt;When starting a new area of code about which we don’t know much yet, we might temporarily suspend our design judgment for a while. We’d just test-drive the behaviour through the public interface of an object without imposing much structure. Doing this allows us time to learn more about the problem and its boundaries before committing to a given structure. We can see this decision as taking a &lt;em&gt;deliberate, prudent technical debt&lt;/em&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are different approaches to get this “room” for learning, such as (from more to less structure-imposing):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We might prefer to consider as peers only those behaviours that we can clearly match with a peer stereotype, (&lt;strong&gt;dependencies&lt;/strong&gt;, &lt;strong&gt;notifications&lt;/strong&gt; or &lt;strong&gt;adjustments&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We might consider as peers only the &lt;strong&gt;dependencies&lt;/strong&gt; which are required to be able to write unit tests (&lt;strong&gt;FIRS&lt;/strong&gt; violations). This approach would result in test boundaries similar to the ones that the classic style of TDD produces&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We might even decide to test-drive the behaviour using only integration tests&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;. In this “extreme” approach, we might end with no peers at all, although we’ll likely need to at least isolate the tests from dependencies that violate the &lt;strong&gt;R&lt;/strong&gt;epeatable and &lt;strong&gt;S&lt;/strong&gt;elf-validating properties form &lt;strong&gt;FIRS&lt;/strong&gt;&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;3-2-signals-that-a-breaking-out-is-necessary&quot;&gt;3. 2. Signals that a &lt;strong&gt;breaking out&lt;/strong&gt; is necessary.&lt;/h2&gt;

&lt;p&gt;After a short while, the object we are test-driving will become too complex to understand because of its poor cohesion&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;. We’ll likely observe code smells like &lt;em&gt;Divergent Change&lt;/em&gt;, &lt;em&gt;Large Class&lt;/em&gt;, &lt;em&gt;Data Clump&lt;/em&gt;, &lt;em&gt;Primitive Obsession&lt;/em&gt;, or &lt;em&gt;Feature Envy&lt;/em&gt;, etc.&lt;/p&gt;

&lt;p&gt;This lack of cohesion may also manifest as testability problems (test smells). The tests are verifying many behaviours at the same time, which means they have a big scope and a lack of focus. This can lead to difficulties in testing the object’s behaviour&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;, or to test failures that become difficult to interpret. We’ll analyze these testability problems in more detail later.&lt;/p&gt;

&lt;p&gt;Note that the impact of poor cohesion on testability may take longer to appear as test smells than as code smells in production code. Therefore, we should monitor the emergence of code smells, as they often serve as earlier indicators that a &lt;strong&gt;breaking out&lt;/strong&gt; may be needed.&lt;/p&gt;

&lt;p&gt;Once we detect a &lt;strong&gt;breaking out&lt;/strong&gt; is needed, we should not wait long to apply it because the longer we defer it, the more friction we’ll face when adding new features and the more expensive applying the &lt;strong&gt;breaking out&lt;/strong&gt; will become&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt;. These effects correspond to the &lt;strong&gt;recurring&lt;/strong&gt; and &lt;strong&gt;accruing&lt;/strong&gt; interests of technical debt, respectively. GOOS authors express their concern that if we defer this cleanup due to time pressure, we may have to assume it in a moment where we “could least afford it”. This may make us feel forced to defer the refactoring even more, making the tech-debt snowball even bigger.&lt;/p&gt;

&lt;h2 id=&quot;3-3-applying-a-breaking-out&quot;&gt;3. 3. Applying a &lt;strong&gt;breaking out&lt;/strong&gt;.&lt;/h2&gt;

&lt;p&gt;We apply it by splitting a large object into smaller collaborating objects and values that each follow the &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;Single Responsibility Principle&lt;/a&gt;&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt;. This refactoring improves overall cohesion by producing a composite object made up of the original object and the extracted objects and values that it now coordinates. After the &lt;strong&gt;breaking out&lt;/strong&gt;, the original object serves as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Facade_pattern&quot;&gt;façade&lt;/a&gt; for the extracted new types and, as the entry point to the composite object, it remains the only object visible to the tests and the rest of the system.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/refactoring_split_large_class.png&quot; alt=&quot;Before and after applying a breaking out.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Before and after applying a breaking out.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;3-3-1-what-kind-of-objects-were-extracted&quot;&gt;3. 3. 1. What kind of objects were extracted?&lt;/h3&gt;

&lt;p&gt;Values are not objects by definition, so we don’t need to consider them. This focus the discussion on the object types introduced by the &lt;strong&gt;breaking out&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After a &lt;strong&gt;breaking out&lt;/strong&gt;, only the original object is visible to the tests and the rest of the system. The new object types are only “seen” by the original object that owns them. Furthermore, we could inline them back into private methods of the original object without affecting the tests or any of its other clients. This means they are an internal detail of the original object, therefore, they are being treated as &lt;strong&gt;internals&lt;/strong&gt;, not &lt;strong&gt;peers&lt;/strong&gt; of the original object.&lt;/p&gt;

&lt;p&gt;Some of those object types will remain as internals, whereas others may be “promoted” to peers. We explain the reasons that make us decide to promote an internal object to be a peer in our next post about &lt;strong&gt;breaking out&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;-3-4-what-about-the-tests&quot;&gt;&lt;a name=&quot;what_about_the_tests&quot;&gt;&lt;/a&gt; 3. 4. What about the tests?&lt;/h2&gt;

&lt;p&gt;After removing the cohesion problems from the production code, &lt;strong&gt;what should we do with the tests?&lt;/strong&gt; They are still testing the behaviours of the original object and its collaborating objects and values through the interface of the original object. This means they are unfocused and likely large.&lt;/p&gt;

&lt;p&gt;The newly extracted internal objects and values provide interfaces that let us test their behaviours independently. We could add more fine-grained and focused tests for them using those interfaces, &lt;strong&gt;but should we?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not necessarily. We should only do it if it’s worth the effort. We may decide to defer testing the new types independently until it brings a clear benefit, or even decide not to test some of them if that doesn’t cause testability problems that are too painful.&lt;/p&gt;

&lt;p&gt;Before deciding, we should take a closer look at the current tests. Let’s examine any testability problems we may find in them and see how they relate to the desirable test properties Kent Beck describes in his &lt;a href=&quot;https://testdesiderata.com/&quot;&gt;test desiderata&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will specifically examine the following properties: &lt;a href=&quot;https://www.youtube.com/watch?v=bDaFPACTjj8&quot;&gt;readability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=CAttTEUE9HM&quot;&gt;writability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;specificity&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt;&lt;a href=&quot;#nota13&quot;&gt;&lt;sup&gt;[13]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;3-4-1-disadvantages&quot;&gt;3. 4. 1. Disadvantages.&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Poor readability and writability&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The size and lack of focus of the composite object’s tests in themselves can make them &lt;em&gt;harder to understand&lt;/em&gt;, which causes &lt;strong&gt;poor readability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In addition, the inputs and outputs we use in some of those tests might be very different from the ones used by some internal behaviour we’re trying to validate. This happens because the more distance from the entry point to the interface of the internal behaviour, the more likely it is that both input and output have been transformed by an intermediate behaviour. This difference in the inputs and outputs at both interfaces might make the test &lt;em&gt;harder to understand&lt;/em&gt;, meaning an &lt;strong&gt;even poorer readability&lt;/strong&gt;, and &lt;em&gt;costlier to write&lt;/em&gt; (they take more effort), introducing &lt;strong&gt;writability problems&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Poor specificity&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another test smell we usually find in unfocused tests are &lt;em&gt;test failures that become difficult to interpret&lt;/em&gt;. This means they may also have &lt;strong&gt;poor specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt; Poor composability&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we compose two behaviours, and each behaviour can vary in multiple ways (e.g., different inputs, configurations, or states), the number of required test cases to exhaustively test all combinations is equal to the cardinality of the Cartesian product of their variations. As we compose more behaviors (or parameters), the total number of possible test cases grows multiplicatively, leading to a combinatorial explosion of test cases.&lt;/p&gt;

&lt;p&gt;Composability is useful for avoiding this phenomenon. By composing different dimensions of variability that result from separating concerns, we can test each dimension separately and then have only a few tests that verify their combination. This allows the number of test cases to grow additively instead of multiplicatively, while still providing confidence that the tests are sufficient.&lt;/p&gt;

&lt;p&gt;To test-drive complex behaviour, keeping a short feedback loop, we need to be able to break it into smaller increments of behaviour (different dimensions of variability). This ability is known as &lt;a href=&quot;https://tidyfirst.substack.com/p/tdds-missing-skill-behavioral-composition&quot;&gt;behavioural composition&lt;/a&gt;. Test-driving a complex behaviour through the composite object’s interface might make it difficult to apply behavioural composition, thereby impairing our ability to apply TDD&lt;a href=&quot;#nota14&quot;&gt;&lt;sup&gt;[14]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we face difficulties in composing behaviours, it means that the original tests have &lt;strong&gt;low composability&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;3-4-2-one-advantage&quot;&gt;3. 4. 2. One advantage.&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt; High structure-insensitivity&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not all it’s bad about the original tests because not knowing anything about the internal details of the original object gives them a &lt;strong&gt;high structure-insensitivity&lt;/strong&gt; which is advantageous to reduce refactoring costs.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/original_tests_properties_no_values_with_labels.png&quot; alt=&quot;Original tests properties.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Original tests properties.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In our next post we’ll use this analysis of test properties to identify the trade-offs involved in deciding whether we should refactor the tests now or later.&lt;/p&gt;

&lt;h2 id=&quot;4-conclusions&quot;&gt;4. Conclusions.&lt;/h2&gt;

&lt;p&gt;In this post, we explained in depth the &lt;strong&gt;breaking out&lt;/strong&gt; technique from &lt;em&gt;Growing Object-Oriented Software, Guided by Tests (GOOS)&lt;/em&gt; belongs to a family of techniques (&lt;strong&gt;breaking out&lt;/strong&gt;, &lt;strong&gt;budding off&lt;/strong&gt;, and &lt;strong&gt;Bundling up&lt;/strong&gt;) that helps discover both object and value types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Breaking out&lt;/strong&gt; is useful to fix the cohesion problems that may arise because of &lt;strong&gt;delaying design decisions until we learn more about the domain&lt;/strong&gt;. This approach may prove useful when facing volatile and poorly understood domains. A &lt;strong&gt;breaking out&lt;/strong&gt; becomes the way to pay that conscious technical debt. We also described how to recognize the need to apply it, using code smells and, in more severe cases, testability problems as indicators of poor cohesion.&lt;/p&gt;

&lt;p&gt;Applying a &lt;strong&gt;breaking out&lt;/strong&gt; splits the initial object into smaller collaborating internal objects and values. The new objects created through this refactoring are treated as &lt;em&gt;internals&lt;/em&gt; rather than &lt;em&gt;peers&lt;/em&gt; since they remain invisible to the tests and other system parts. After this refactoring, the original tests still have poor readability, writability, specificity, and composability. Despite these disadvantages, such tests have high structure-insensitivity, meaning they are resilient to refactorings affecting the interfaces of the new types.&lt;/p&gt;

&lt;p&gt;Our next post will focus on &lt;strong&gt;when and how to refactor the original tests&lt;/strong&gt;. It will be through that refactoring that new &lt;em&gt;peers&lt;/em&gt; may appear in our design.&lt;/p&gt;

&lt;p&gt;Thanks for coming to the end of this post. We hope that what we explain here will be useful to you.&lt;/p&gt;

&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;
&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@icon0/&quot;&gt;icon0&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/35957157-thinking-in-bets&quot;&gt;Thinking in Bets: Making Smarter Decisions When You Don’t Have All the Facts&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Annie_Duke&quot;&gt;Anne Duke&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20090807004827/http://msdn.microsoft.com/en-ca/magazine/dd882516.aspx&quot;&gt;Test-Driven Design Using Mocks And Tests To Design Role-Based Objects&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/%F0%9F%92%BBisaiah-perumalla-8537563/&quot;&gt;Isaiah Perumalla&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;,  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://testdesiderata.com/&quot;&gt;Test Desiderata&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] These are the posts mentioned in the introduction:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt; in which we commented, among other things, the importance of distinguishing an object’s peers from its internals in order to write maintainable unit tests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt; in which we explained how the &lt;strong&gt;peer stereotypes&lt;/strong&gt; helped us identify an object’s peers.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] In a section titled &lt;em&gt;Where Do Objects Come From?&lt;/em&gt;. We mention the section because we think that its title is important to understand the context of these techniques. It is located in chapter 7, &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] This mind map comes from a talk which was part of the &lt;strong&gt;Mentoring Program in Technical Practices&lt;/strong&gt; we taught last year in &lt;a href=&quot;https://www.domingoalonsogroup.com/es/empresas/aida&quot;&gt;AIDA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] The techniques for value types are explained in the section &lt;em&gt;Value Types&lt;/em&gt; and the ones for object types are explained in subsection &lt;em&gt;Breaking Out: Splitting a Large Object into a Group of Collaborating Objects&lt;/em&gt; from section, &lt;em&gt;Where Do Objects Come From?&lt;/em&gt;. Both sections are in chapter 7 of GOOS book: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] See Martin Fowler’s post &lt;a href=&quot;https://martinfowler.com/bliki/TechnicalDebtQuadrant.html&quot;&gt;Technical Debt Quadrant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] We talked about how this approach produces boundaries similar to the ones obtained applying the classic style of TDD in our post &lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://stevefenton.co.uk/about-me/&quot;&gt;Steve Fenton&lt;/a&gt;’s posts &lt;a href=&quot;https://stevefenton.co.uk/blog/2013/05/my-unit-testing-epiphany/&quot;&gt;My unit testing epiphany&lt;/a&gt; and &lt;a href=&quot;https://stevefenton.co.uk/blog/2013/05/my-unit-testing-epiphany-continued/&quot;&gt;My unit testing epiphany continued&lt;/a&gt; describe this approach well. His epiphany consisted in realizing the class is not the unit. His explanation is influenced by Ian Cooper’s 2013 influential talk &lt;a href=&quot;https://www.infoq.com/presentations/tdd-original/&quot;&gt;TDD, Where Did It All Go Wrong&lt;/a&gt; and uses hexagonal architecture’s &lt;strong&gt;port&lt;/strong&gt; concept. The following table expresses how he understood some concepts before his epiphany and how he understands them after it:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/breaking-out/test-epiphany-table.png&quot; alt=&quot;Test terminology in My unit testing epiphany continued blog post&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Test terminology in &quot;My unit testing epiphany continued&quot; blog post.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] In this discussion we consider &lt;strong&gt;integration tests&lt;/strong&gt; as tests that check whether different units work together as expected, but remember that we don’t consider the class as the unit. Integration tests can, and usually, involve external systems, the ones you leave out to get isolated and faster unit tests (database, file, shared memory, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] We need integration tests to at least be &lt;strong&gt;R&lt;/strong&gt;epeatable to avoid flakiness, and &lt;strong&gt;S&lt;/strong&gt;elf-validating to enable test automation. Have a look at the discussion about integration tests in our post &lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] This time might be shorter than we think. In the paper &lt;a href=&quot;https://www.researchgate.net/publication/297737807_When_and_Why_Your_Code_Starts_to_Smell_Bad&quot;&gt;When and Why Your Code Starts to Smell Bad&lt;/a&gt; Tufano et al surprisingly found that the changes that were the root cause of cases of the code smell &lt;strong&gt;Blob class&lt;/strong&gt; (a.k.a. &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=20&quot;&gt;Large Class&lt;/a&gt;) were introduced already upon the creation of those classes, and not due to their evolution with time as is widely thought. In any case, the more we wait to fix cohesion problems, the harder it will get to fix them.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] &lt;a href=&quot;https://github.com/trikitrok/discovering-objects-talk-examples/blob/main/breaking-out/user-account-creation/UserAccount.Tests/UserAccountCreationTest.cs&quot;&gt;This code&lt;/a&gt; is an example of unfocused tests that are becoming too large to validate the object’s behaviour easily (it was used in a mentoring program we did last year in &lt;a href=&quot;https://www.domingoalonsogroup.com/es/empresas/aida&quot;&gt;AIDA&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Only a couple of the test cases in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserAccountCreationTest&lt;/code&gt; serve to check the behaviour of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserAccountCreation&lt;/code&gt;. Most of them are actually testing the logic to validate the user’s document id. Since we still need to test-drive other behaviours to validate other parts of the user data, those tests will grow even larger and more unfocused. That’s why we think we should refactor these tests before we keep on developing.&lt;/p&gt;

&lt;p&gt;It’s kind of difficult to create synthetic examples of tests that express this problem well. A real example might likely be much larger and complex than the example we showed you here. We hope the message, somehow, gets across.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] If the lack of cohesion has gone too far, reading &lt;a href=&quot;https://oorp.github.io/#split-up-god-class&quot;&gt;Split Up God Class&lt;/a&gt; from &lt;a href=&quot;https://oorp.github.io/&quot;&gt;Object-Oriented Reengineering Patterns&lt;/a&gt;, chapter 20 of &lt;a href=&quot;https://www.oreilly.com/library/view/working-effectively-with/0131177052/&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt; or the &lt;strong&gt;Splinter pattern&lt;/strong&gt; from &lt;a href=&quot;https://pragprog.com/titles/atevol/software-design-x-rays/&quot;&gt;Software Design X-Rays&lt;/a&gt; might be helpful. You may also have a look at an interesting documented example of refactoring a large class:
&lt;a href=&quot;https://martinfowler.com/articles/class-too-large.html&quot;&gt;Refactoring: This class is too large&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These techniques won’t be necessary if we don’t defer the &lt;strong&gt;breaking out&lt;/strong&gt; too much.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12] We may get that splitting of responsibilities applying refactorings, such as, &lt;a href=&quot;https://refactoring.guru/extract-class&quot;&gt;Extract Class&lt;/a&gt;, &lt;a href=&quot;https://www.industriallogic.com/refactoring-to-patterns/catalog/conditionalWithStrategy.html&quot;&gt;Replace Conditional Logic With Strategy&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota13&quot;&gt;&lt;/a&gt; [13] There are many other desirable test properties in Beck’s &lt;a href=&quot;https://testdesiderata.com/&quot;&gt;test desiderata&lt;/a&gt;, but we considered that &lt;a href=&quot;https://www.youtube.com/watch?v=bDaFPACTjj8&quot;&gt;readability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=CAttTEUE9HM&quot;&gt;writability&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;specificity&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;structure-insensitivity&lt;/a&gt; were the most relevant to discuss the trade-offs involved in a &lt;strong&gt;breaking out&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota14&quot;&gt;&lt;/a&gt; [14] We think that &lt;a href=&quot;https://www.youtube.com/watch?v=Wf3WXYaMt8E&quot;&gt;composability&lt;/a&gt; is one of the test properties that have more impact on our ability to do TDD in short feedback loops (small behaviour increments). Sometimes the only way to be able to apply behavioural composition is to introduce a separation of concerns in the production code.&lt;/p&gt;

</description>
          <pubDate>2025-11-10T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/11/breaking-out-to-improve-cohesion</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/11/breaking-out-to-improve-cohesion</guid>
        </item>
      
    
      
        <item>
          <title>Nuestro flujo de decisión para refinar Historias de Usuario poco antes de empezar a desarrollarla</title>
          <description>&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;

&lt;p&gt;En un &lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;post anterior&lt;/a&gt; exploramos el tamaño y el nivel de detalle adecuados que debe tener una historia de usuario, e identificamos dos momentos clave en los que conviene refinarlas, que a continuación mostramos en orden cronológico:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;T&lt;sub&gt;r&lt;/sub&gt;, que ocurre poco antes de presentar una historia al equipo.&lt;/li&gt;
  &lt;li&gt;T&lt;sub&gt;c&lt;/sub&gt;, que ocurre poco antes del momento de empezar a desarrollar una historia, T&lt;sub&gt;d&lt;/sub&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En este post describimos el flujo de decisión que seguimos para facilitar el refinamiento de historias de usuario en el momento T&lt;sub&gt;c&lt;/sub&gt;.&lt;/p&gt;

&lt;h2 id=&quot;nuestro-flujo-de-decisión-para-refinar-historias-de-usuario-poco-antes-de-empezar-a-desarrollarlas&quot;&gt;Nuestro flujo de decisión para refinar historias de usuario poco antes de empezar a desarrollarlas.&lt;/h2&gt;

&lt;p&gt;T&lt;sub&gt;c&lt;/sub&gt; es un momento clave en el que podríamos plantearnos ciertas preguntas que nos permitirán refinar nuestras historias de usuario lo suficiente como para que podamos desarrollarlas de forma fluida. Estas preguntas&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; se basan en los criterios  &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; que nos ayudan a evaluar lo adecuada que es una historia de usuario.&lt;/p&gt;

&lt;p&gt;En el siguiente diagrama mostramos el flujo de decisión que seguimos en T&lt;sub&gt;c&lt;/sub&gt; para cada una de las historias de usuario.&lt;/p&gt;

&lt;figure&gt;
&lt;a href=&quot;https://github.com/Codesai/website/blob/main/assets/posts/flujo-refinar-HU-en-Tc/flow-before-develop-feature.png&quot;&gt;
&lt;img src=&quot;/assets/posts/flujo-refinar-HU-en-Tc/flow-before-develop-feature.png&quot; alt=&quot;Flujo de decisión para refinar historias poco antes de comenzar su desarrollo&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;/a&gt;
&lt;figcaption&gt;&lt;strong&gt;Flujo de decisión para refinar historias poco antes de comenzar su desarrollo&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Para cada una de las historias que pensamos refinar, lo primero es preguntarnos si la historia cumple con los criterios &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si la historia cumple todos los criterios INVEST, entonces quiere decir que está lista para ser desarrollada y podemos pasar a la siguiente.&lt;/p&gt;

&lt;p&gt;En caso de no cumplir alguno de los criterios, tendremos que preguntarnos si el incumplimiento supone realmente un problema en nuestro contexto&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En caso que el incumplimiento sí que sea un problema, hay que preguntarse si el problema es que la historia de usuario ha dejado de tener valor.&lt;/p&gt;

&lt;p&gt;En caso de que ya no tenga valor, deberíamos descartarla y pasar a la siguiente. Eliminar historias sin valor del backlog es muy importante para &lt;a href=&quot;https://www.youtube.com/watch?v=paK4jfGpOJY&quot;&gt;no generar waste&lt;/a&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En caso de que la historia siga siendo valiosa debemos refinarla. La forma de refinarla dependerá del criterio INVEST que incumple.&lt;/p&gt;

&lt;p&gt;Una vez refinada la historia de usuario, tendremos que volver a evaluarla para verificar si ahora sí que cumple con INVEST.&lt;/p&gt;

&lt;h3 id=&quot;cómo-evaluar-cada-criterio-y-refinarlo-si-se-incumple&quot;&gt;Cómo evaluar cada criterio y refinarlo si se incumple.&lt;/h3&gt;

&lt;p&gt;Para facilitar la evaluación de los criterios INVEST, hemos relacionado cada uno de ellos con preguntas clave que nos pueden ayudar a razonar si los estamos incumpliendo. Además, hemos añadido el refinamiento específico que puede corregir el incumplimiento de cada uno de los criterios.&lt;/p&gt;

&lt;figure&gt;
&lt;a href=&quot;https://github.com/Codesai/website/blob/main/assets/posts/flujo-refinar-HU-en-Tc/flow-before-develop-feature-refined-in-deep.png&quot;&gt;
&lt;img src=&quot;/assets/posts/flujo-refinar-HU-en-Tc/flow-before-develop-feature-refined-in-deep.png&quot; alt=&quot;Preguntas clave y refinamientos por criterio&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;/a&gt;
&lt;figcaption&gt;&lt;strong&gt;Preguntas clave y refinamientos por criterio&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;por-qué-nos-resultan-útiles-estas-preguntas-clave-y-estos-refinamientos-para-cada-criterio-invest-en-tc&quot;&gt;¿Por qué nos resultan útiles estas preguntas clave y estos refinamientos para cada criterio INVEST en T&lt;sub&gt;c&lt;/sub&gt;?&lt;/h4&gt;

&lt;p&gt;Analicemos cada uno de los criterios por separado para entender mejor los motivos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;a href=&quot;https://xp123.com/independent-stories-in-the-invest-model/&quot;&gt;Independent (I)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Antes de empezar a desarrollar nos interesa que las historias de usuario sean independientes. Que una historia de usuario sea independiente de otras quiere decir que representa un aspecto funcional disjunto del sistema, y esto facilitará que se puedan comprender, implementar y probar de manera aislada. De modo que lograr que una historia sea independiente tiene un impacto directo en el desarrollo de su funcionalidad.&lt;/p&gt;

&lt;p&gt;Consideraremos dos tipos de dependencia&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Solape.&lt;/li&gt;
  &lt;li&gt;Orden.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto significa que debemos hacernos las siguientes preguntas al evaluar el criterio de independencia:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;¿Existe solape entre las historias de usuario?&lt;/li&gt;
  &lt;li&gt;¿Debemos hacer las historias en un orden determinado?&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;dependencia-por-solape&quot;&gt;Dependencia por Solape.&lt;/h5&gt;

&lt;p&gt;Es la que suele ser más problemática ya que genera confusión y puede dar lugar a los siguientes problemas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Que nos olvidemos de desarrollar alguna funcionalidad.&lt;/li&gt;
  &lt;li&gt;Que desarrollemos alguna funcionalidad más de una vez.&lt;/li&gt;
  &lt;li&gt;Que no podamos desarrollarlas en paralelo, lo que afectará a cómo se puede organizar el equipo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El solape se puede eliminar reescribiendo las historias.&lt;/p&gt;

&lt;p&gt;Pongamos un ejemplo de historias de usuario solapadas y veamos cómo se podría resolver.&lt;/p&gt;

&lt;p&gt;Imaginemos que tenemos las siguientes historias.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Mostrar los trabajadores de la empresa y mostrar las ofertas laborales de la empresa.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Mostrar los trabajadores de la empresa y poder enviar un mensaje a la empresa.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ambas historias incluyen la funcionalidad de “Mostrar los trabajadores de la empresa”. Tal como están escritas estas historias se podrían hacer en cualquier orden por lo que estamos ante un problema puramente de solape.&lt;/p&gt;

&lt;p&gt;Una manera sencilla de resolverlo, sería separar la funcionalidad que es común&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;, quedando de la siguiente manera:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Mostrar los trabajadores de la empresa.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Mostrar las ofertas laborales de la empresa.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Enviar un mensaje a la empresa.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;h5 id=&quot;dependencia-de-orden&quot;&gt;Dependencia de Orden.&lt;/h5&gt;

&lt;p&gt;Si tenemos dos historias de usuario A y B, y el desarrollo de B no puede empezar hasta que no hayamos desarrollado A, existe una dependencia de orden de desarrollo entre las historias A y B que denotaremos como A -&amp;gt; B.&lt;/p&gt;

&lt;p&gt;Podríamos liberar esta restricción del orden de desarrollo simulando la funcionalidad de A. Simular la funcionalidad de A consistiría en crear la versión más simple posible de A que permita desarrollar B.&lt;/p&gt;

&lt;p&gt;Veámoslo mejor con un ejemplo.&lt;/p&gt;

&lt;p&gt;Si tenemos las siguientes historias:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Crear un factura.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Marcar la factura como pagada.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Necesitamos desarrollar “Crear una factura” antes que “Marcar la factura como pagada” porque debe existir una factura que se pueda marcar como pagada. Esto significa que existe una dependencia de orden entre ellas: “Crear factura” -&amp;gt; “Marcar factura como pagada”.&lt;/p&gt;

&lt;p&gt;En este caso podríamos simular “Crear factura”, por ejemplo, hardcodeando los datos de una factura. Esto permitiría desarrollar “Marcar factura como pagada” antes que “Crear factura”.&lt;/p&gt;

&lt;p&gt;Es importante darse cuenta de que no podríamos usar en producción “Marcar factura como pagada” hasta no haber desarrollado “Crear factura”.&lt;/p&gt;

&lt;p&gt;Así que no se puede eliminar la dependencia de orden de la funcionalidad, pero sí que podemos eliminar la dependencia de orden del desarrollo.&lt;/p&gt;

&lt;p&gt;Poder desarrollar las historias en cualquier orden puede ser beneficioso, porque nos permite priorizar, ya sea por valor o riesgo, la exploración de determinadas funcionalidades, y así maximizar nuestro aprendizaje:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Priorizar aquellas funcionalidades con más valor para los clientes para buscar feedback más temprano y validarlas.&lt;/li&gt;
  &lt;li&gt;Abordar cuanto antes los posibles riesgos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aunque no siempre es posible solucionar la dependencia de orden, esta suele generar menos problemas que la dependencia por solape &lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;a href=&quot;https://xp123.com/negotiable-stories-in-the-invest-model/&quot;&gt;Negotiable (N)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Las partes implicadas en crear un producto deberían colaborar para acordar qué funcionalidad es necesario desarrollar. Para que esta colaboración sea efectiva, debemos mantener nuestras opciones abiertas&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para evitar reducir nuestras opciones debemos evaluar si la historia está sobrespecificando la solución. Es decir, si está más centrada en el “cómo hay que hacerlo” que en el “qué hay que hacer”.&lt;/p&gt;

&lt;p&gt;Fíjense que estamos eligiendo centrar la evaluación de la capacidad de negociar solo en el “cómo” y dejar fuera de la discusión el “qué”. Hemos decidido hacerlo así por pragmatismo&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si la historia estuviese sobrespecificada tendríamos que valorar y discutir alternativas para ampliar el horizonte de soluciones. Con esto quizás encontremos alternativas más baratas, eficientes y/o que no especifiquen detalles de implementación.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;a href=&quot;https://xp123.com/valuable-stories-in-the-invest-model/&quot;&gt;Valuable (V)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Todo incremento de funcionalidad debe aportar valor y, por tanto, siempre debemos cuestionar si una historia de usuario lo tiene&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;. Además, debemos hacer este cuestionamiento de forma continua para entregar en todo momento el máximo valor posible.&lt;/p&gt;

&lt;p&gt;Algunos motivos por lo que una historia podría perder valor son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Se han dado argumentos que cuestionan su valor en alguna conversación.&lt;/li&gt;
  &lt;li&gt;El contexto ha cambiado (problema o prioridades).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hay que tener en cuenta que el valor es relativo, siempre estamos comparando unas historias con otras. Esto significa que lo que solemos observar es que una historia pierde valor con respecto a otras.&lt;/p&gt;

&lt;p&gt;Sin embargo, al disponer de recursos limitados, debemos priorizar las historias según su valor, y seleccionar algunas de las más valiosas para desarrollar a continuación.&lt;/p&gt;

&lt;p&gt;Debemos hacernos dos preguntas con respecto al valor:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;¿Tiene valor?&lt;/li&gt;
  &lt;li&gt;¿Todos perciben claramente el mismo valor?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si no conseguimos verle valor a una historia, lo mejor es descartarla&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Que no todos perciban el mismo valor podría deberse a un problema de comunicación. En ese caso, tendríamos que explicar mejor la historia para aclarar su valor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. &lt;a href=&quot;https://xp123.com/estimable-stories-in-the-invest-model/&quot;&gt;Estimable (E)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para poder estimar una historia primero tenemos que ser capaces de entenderla.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo verdaderamente útil de estimar una historia es identificar y examinar la incertidumbre que encierra&lt;/strong&gt;, no asignarle una cifra al esfuerzo (tiempo) necesario para desarrollarla.&lt;/p&gt;

&lt;p&gt;Reducir la incertidumbre nos ayudará a desarrollar una historia de forma más fluida, y al mismo tiempo, esto hará que su estimación será más precisa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El origen de la incertidumbre puede venir del espacio del problema o del espacio de la solución&lt;/strong&gt;. Por ejemplo, la incertidumbre causada por el desconocimiento del dominio vendría del espacio del problema, mientras que la incertidumbre causada por tener poca experiencia en alguna tecnología que necesitamos usar vendría del espacio de la solución.&lt;/p&gt;

&lt;p&gt;Distintos miembros del equipo pueden percibir la incertidumbre de una historia de usuario de forma diferente. Esto hace que sea muy importante fomentar que todos los miembros del equipo participen en la discusión sobre la incertidumbre de la historia de usuario (su estimación).&lt;/p&gt;

&lt;p&gt;Así que podríamos hacernos la siguiente secuencia de preguntas:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;¿Hay incertidumbre en el espacio del problema?.&lt;/li&gt;
  &lt;li&gt;¿Hay incertidumbre en el espacio de la solución?.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El orden en que nos hacemos estas preguntas es importante, ya que definir mejor el problema podría aclarar la solución.&lt;/p&gt;

&lt;p&gt;En caso de haya incertidumbre en el espacio de la solución debido a un desconocimiento de alguna tecnología podríamos reducirla o incluso eliminarla mediante una &lt;a href=&quot;https://en.wikipedia.org/wiki/Spike_(software_development)&quot;&gt;spike&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En otros casos “añadir más detalles” podría ser una buena forma de reducir la incertidumbre (en un próximo post profundizaremos en qué significa “añadir más detalles”).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. &lt;a href=&quot;https://xp123.com/small-scalable-stories-in-the-invest-model/&quot;&gt;Small (S)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En el momento T&lt;sub&gt;c&lt;/sub&gt; nos interesa que las historias sean lo más pequeñas posibles&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt; para poder:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Entregar valor lo antes posible.&lt;/li&gt;
  &lt;li&gt;Reducir riesgos.&lt;/li&gt;
  &lt;li&gt;Conseguir ciclos de feedback cortos que nos permitan ajustar prioridades y tomar mejores decisiones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Debemos plantearnos si existe alguna partición de la historia de usuario que pueda ayudarnos a mejorar alguno de esos aspectos.&lt;/p&gt;

&lt;p&gt;Nuestra recomendación es usar de forma sistemática catálogos de heurísticas de partición de historias que nos permitan explorar todas las opciones de partición existentes&lt;a href=&quot;#nota13&quot;&gt;&lt;sup&gt;[13]&lt;/sup&gt;&lt;/a&gt;. Pensamos que esta recomendación puede ser valiosa tanto para equipos con poca experiencia en partir historias a los que les servirá de guía, como para equipos con experiencia que pueden usarlo para no depender exclusivamente de su memoria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. &lt;a href=&quot;https://xp123.com/testable-stories-in-the-invest-model/&quot;&gt;Testable (T)&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Que una historia sea testeable nos sirve tanto para evitar malentendidos y suposiciones erróneas, como para saber cuándo está acabada y funcionando cómo se esperaba&lt;a href=&quot;#nota14&quot;&gt;&lt;sup&gt;[14]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una historia se considera testeable si dados unos inputs determinados, podemos ponernos de acuerdo sobre el comportamiento esperado del sistema y/o sus efectos observables.&lt;/p&gt;

&lt;p&gt;Para ello debemos eliminar cualquier ambigüedad que pueda contener la historia.&lt;/p&gt;

&lt;p&gt;Creemos que añadir criterios de aceptación&lt;a href=&quot;#nota15&quot;&gt;&lt;sup&gt;[15]&lt;/sup&gt;&lt;/a&gt; y ejemplos a una historia de usuario es la manera más efectiva de eliminar su ambigüedad. Así que tiene sentido preguntarnos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;¿Tiene criterios de aceptación suficientes?&lt;/li&gt;
  &lt;li&gt;En caso que sí, ¿son claros y contienen ejemplos?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tanto si faltan criterios de aceptación, hay criterios que no son claros o les faltan ejemplos, debemos detallar más la historia para ayudar a aclarar lo que se necesita.&lt;/p&gt;

&lt;p&gt;En un próximo post profundizaremos en qué significa detallar más una historia.&lt;/p&gt;

&lt;h2 id=&quot;resumen&quot;&gt;Resumen.&lt;/h2&gt;

&lt;p&gt;En este post hemos descrito y analizado el flujo de decisión basado en los criterios INVEST que seguimos para facilitar el refinamiento de historias de usuario antes de comenzar su desarrollo.&lt;/p&gt;

&lt;p&gt;Este flujo usa una serie de preguntas clave para evaluar si una historia incumple alguno de los criterios INVEST, y en caso de incumplimiento nos indica los refinamientos adecuados para mejorarla.&lt;/p&gt;

&lt;p&gt;Refinar una historia puede ayudarnos a entregar su valor lo antes posible, reducir riesgos, reducir retrabajo y tener ciclos de feedback más cortos.&lt;/p&gt;

&lt;p&gt;Esperamos que este flujo de decisión, o los conceptos de los que les hemos hablado en este post, les puedan resultar útiles.&lt;/p&gt;

&lt;h2 id=&quot;serie-historias-de-usuario&quot;&gt;Serie Historias de Usuario.&lt;/h2&gt;
&lt;p&gt;Este post es parte de una serie sobre Historias de usuario:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Nuestro flujo de decisión para refinar Historias de Usuario poco antes de empezar a desarrollarla.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2026/03/detallando-historias&quot;&gt;Detallando historias de usuario para acotarlas y reducir su ambigüedad&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Quisieramos agradecer a &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Toño de la Torre&lt;/a&gt; y a
&lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt; por revisar y darnos feedback sobre el contenido de este post.&lt;/p&gt;

&lt;p&gt;Finalmente, también quisieramos agradecer a &lt;a href=&quot;https://www.pexels.com/@cottonbro/&quot;&gt;cottonbro studio&lt;/a&gt; por su foto.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Las preguntas que nos planteamos en el flujo de decisión que presentamos están pensadas para ayudarnos a conseguir historias listas para ser desarrolladas. Nuestra intención no es buscar la perfección. Al aplicarlo debemos evitar caer en parálisis por análisis. Con este flujo solamente intentamos reducir problemas que la falta de refinamiento puede ocasionar durante el desarrollo, como, por ejemplo, dudas o malentendidos evitables que causan retrabajo y/o retrasan la entrega, aportar poco valor, etc.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Los criterios INVEST nos han dado muy buenos resultados para refinar las historias de usuario y además están muy bien documentados. Si en el futuro encontramos otro conjunto de criterios que nos sean más útiles para el refinamiento de historias, los adoptaríamos. Es decir, nos centramos en INVEST porque es lo que hasta ahora nos ha sido más útil.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] La evaluación de estos criterios no ha de aplicarse de manera estricta como si fueran un conjunto de reglas a seguir. Es mejor verlos más bien como una guía.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Si acumulamos historias de usuario sin valor en vez de descartarlas, invertiremos más energía de la necesaria en gestionar el backlog. En un caso extremo podríamos acabar en el antipatrón “Story card hell”, descrito por James Shore como “[…] when you have 300 story cards and you have to keep track of them all” en su post &lt;a href=&quot;https://www.jamesshore.com/v2/presentations/2005/beyond-story-cards&quot;&gt;Beyond Story Cards: Agile Requirements Collaboration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nos gustaría hacer notar que en un &lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;post anterior&lt;/a&gt; explicamos cómo se podría llegar a este antipatrón por un motivo diferente: hacer todas las historias demasiados pequeñas en un momento alejado de T&lt;sub&gt;r&lt;/sub&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] William Wake nos habla de otro tipo de dependencia, &lt;a href=&quot;https://xp123.com/independent-stories-in-the-invest-model/&quot;&gt;containment dependency&lt;/a&gt; que ocurre cuando existe una organización jerárquica de varias historias de usuario. En nuestra experiencia las dependencias por solape y orden son más frecuentes así que preferimos ignorar la dependencia por &lt;strong&gt;containment&lt;/strong&gt; en aras de la simplicidad.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] En algunas ocasiones, al intentar solucionar una dependencia por solape aparecerá una dependencia de orden.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Algunos motivos por los que creemos que la dependencia de orden genera menos problemas que la dependencia por solape, son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Cuando la propia naturaleza del problema lleva implícita un orden.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Cuando los participantes han asumido un orden, a veces debido a que han tenido experiencias en contextos similares.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo, las siguientes historias:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Envíar un mensaje.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Reenvíar un mensaje.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tienen una dependencia de orden, pero por la naturaleza del problema es altamente probable que primero hagamos “Envíar un mensaje” antes que “Reenvíar un mensaje”. Los problemas ocurren cuando no es claro qué orden establecer.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Martin Fowler habla del concepto de &lt;a href=&quot;https://martinfowler.com/bliki/DecreedStories.html&quot;&gt;Decreed Stories&lt;/a&gt; para aquellas historias en las que no hay conversación. En contraposición está el concepto de &lt;a href=&quot;https://martinfowler.com/bliki/ConversationalStories.html&quot;&gt;Conversational Stories&lt;/a&gt; en la que la conversación es el núcleo de las historias y que recoge el criterio de Negotiable de &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] Tener capacidad de negociar “qué hay que hacer” puede tener un gran impacto en el trabajo con historias de usuario.&lt;/p&gt;

&lt;p&gt;Sin embargo, conseguir poder negociar el “qué” puede implicar modificar el modelo de colaboración existente en un equipo, o incluso, una organización entera. Cambiar las dinámicas de una organización es un problema muy complejo que se sale del ámbito de la discusión del flujo de decisión para refinar historias que estamos presentando.&lt;/p&gt;

&lt;p&gt;Por eso, preferimos centrarnos tan solo en “el cómo” (la sobrespecificación), al ser en nuestra experiencia, más accionable a la escala de una historia de usuario.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] En este &lt;a href=&quot;https://codesai.com/posts/2020/06/caring&quot;&gt;post&lt;/a&gt; ampliamos el concepto de valor, normalmente acotado a la funcionalidad, para que  también incluya aquellos trabajos de cuidado destinados a mantener la sostenibilidad del sistema.&lt;/p&gt;

&lt;p&gt;En este &lt;a href=&quot;https://codesai.com/posts/2024/09/atributos-historias-de-usuario-en-agile-sur&quot;&gt;otro post&lt;/a&gt; hablamos sobre la importancia de los atributos de calidad, a menudo denominados requisitos no funcionales (aunque esta etiqueta puede ser engañosa) y su relación con las historias de usuario.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] No ver valor en una historia de usuario podría estar causado porque falta la perspectiva de alguna parte interesada (&lt;em&gt;stakeholder&lt;/em&gt;). Si fuera así, no deberíamos descartar la historia, sino tener una nueva conversación sobre ella en la que incluyamos a dicha parte interesada.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12] El criterio de &lt;strong&gt;Small&lt;/strong&gt; ha generado bastante confusión.&lt;/p&gt;

&lt;p&gt;Bill Wake ahora prefiere usar el concepto &lt;strong&gt;Scalable&lt;/strong&gt;, “I now use another S […]: Scalable”, porque cree que captura mejor la idea de que una historia debe cambiar en tamaño o escala para adecuarse al momento en el que se encuentre.&lt;/p&gt;

&lt;p&gt;Para profundizar más lean su post &lt;a href=&quot;https://xp123.com/small-scalable-stories-in-the-invest-model/&quot;&gt;Small – Scalable – Stories in the INVEST Model&lt;/a&gt;. Nuestro post &lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?&lt;/a&gt; también habla de este aspecto.&lt;/p&gt;

&lt;p&gt;En el post actual usamos &lt;strong&gt;Small&lt;/strong&gt; en vez de &lt;strong&gt;Scalable&lt;/strong&gt; porque estamos analizando el refinamiento que se da poco antes de empezar a desarrollar la historia, y ahí no cabe confusión posible: la historia de usuario debe de ser lo más pequeña posible.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota13&quot;&gt;&lt;/a&gt; [13] Hay varias heurísticas interesantes que nos pueden indicar posibles particiones. En este artículo hablamos sobre &lt;a href=&quot;https://codesai.com/posts/2020/05/spidr&quot;&gt;SPIDR&lt;/a&gt;, que puede ser un buen punto de partida. En el curso de &lt;a href=&quot;https://codesai.com/cursos/user-stories/&quot;&gt;Historias de Usuario&lt;/a&gt; nos basamos en el trabajo de &lt;a href=&quot;https://xp123.com/twenty-ways-to-split-stories/&quot;&gt;Bill Wake&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota14&quot;&gt;&lt;/a&gt; [14] La confirmación es uno de los aspectos esenciales enunciados por Ron Jeffries en su post de 2001, &lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;Card, Conversation, Confirmation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota15&quot;&gt;&lt;/a&gt; [15] Algunos autores usan otros términos para hablar de los &lt;strong&gt;criterios de aceptación&lt;/strong&gt;. Por ejemplo, Mike Cohn prefiere hablar de &lt;a href=&quot;https://www.mountaingoatsoftware.com/blog/clarifying-the-relationship-between-definition-of-done-and-conditions-of-sa&quot;&gt;conditions of satisfaction&lt;/a&gt;, mientras que en &lt;a href=&quot;https://cucumber.io/blog/bdd/example-mapping-introduction/&quot;&gt;Example Mapping&lt;/a&gt; se utiliza el concepto de &lt;strong&gt;rules&lt;/strong&gt;.&lt;/p&gt;
</description>
          <pubDate>2025-10-08T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/10/flujo-refinar-HU-en-Tc</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/10/flujo-refinar-HU-en-Tc</guid>
        </item>
      
    
      
        <item>
          <title>La clase no es la unidad en el estilo de TDD de Londres</title>
          <description>&lt;p&gt;Este post es una traducción del post original en inglés: &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;

&lt;h4 id=&quot;una-idea-errónea-y-peligrosa-considerar-que-la-clase-es-la-unidad-al-escribir-test-unitarios&quot;&gt;Una idea errónea y peligrosa: considerar que la clase es la unidad al escribir test unitarios.&lt;/h4&gt;

&lt;p&gt;Considerar que la clase es la unidad en los test unitarios tiene efectos terribles. 
Si seguimos esta idea, usaremos dobles de prueba para aislar la clase que estamos testeando de cualquier clase que colabore con ella (sus colaboradores). 
Esto producirá tests altamente acoplados a detalles de implementación y por tanto muy frágiles. Dichos tests serán muy sensibles a la estructura del código&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/unit_is_the_class.png&quot; alt=&quot;Considerando la clase como la unidad...&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Considerando la clase como la unidad...&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Esta fragilidad hará que las refactorizaciones que afecten a interfaces a las que nuestros tests estén acopladas sean más caras (tomarán más tiempo&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;), 
ya que nos veríamos forzados a cambiar también los tests. Este incremento en el coste puede convertirse en un obstáculo para refactorizar.&lt;/p&gt;

&lt;p&gt;Muchos problemas al usar dobles de prueba son causados únicamente por esta idea errónea de considerar la clase como la unidad. 
Afortunadamente, esta idea parece estar retrocediendo, ya que cada vez más desarrolladores están empezando a entender 
que la unidad en los test unitarios debe ser el comportamiento y no la clase. 
Enteder esto ayuda a producir tests menos sensibles a la estructura que no obstaculizan la refactorización.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/unit_is_not_the_class.png&quot; alt=&quot;La clase no es la unidad.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;La clase no es la unidad.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;una-idea-errónea-que-persiste-considerar-que-la-clase-es-la-unidad-en-el-estilo-de-tdd-de-la-escuela-de-londres-o-estilo-mockist&quot;&gt;Una idea errónea que persiste: considerar que la clase es la unidad en el estilo de TDD de la Escuela de Londres o estilo Mockist.&lt;/h4&gt;

&lt;p&gt;Recientemente, hemos notado muchos videos, publicaciones e incluso libros &lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; que afirman que el llamado estilo mockist de TDD considera que la clase es la unidad en los test unitarios.&lt;/p&gt;

&lt;p&gt;Desafortunadamente, esta otra idea errónea sigue estando muy extendida y está provocando que, o bien, algunos desarrolladores apliquen el estilo mockist de TDD de manera completamente incorrecta 
(probando cada clase en aislamiento de sus colaboradores), 
o bien, que decidan no usar dicho estilo en absoluto para evitar los problemas asociados a considerar que “la clase es la unidad” que describimos antes.&lt;/p&gt;

&lt;p&gt;En el resto de esta post, mostraremos como &lt;em&gt;el estilo mockist de TDD &lt;strong&gt;no&lt;/strong&gt; considera que la clase sea la unidad en los test unitarios&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Durante todo el resto de nuestra discusión, usaremos el libro &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt; (GOOS) de &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt; como referencia.&lt;/p&gt;

&lt;h2 id=&quot;la-clase-tampoco-es-la-unidad-en-el-estilo-mockist-de-tdd&quot;&gt;La clase tampoco es la unidad en el estilo mockist de TDD.&lt;/h2&gt;

&lt;h4 id=&quot;prueba-1-valores-y-objetos&quot;&gt;Prueba 1: Valores y Objetos.&lt;/h4&gt;

&lt;p&gt;En la sección &lt;em&gt;Values and Objects&lt;/em&gt; (capítulo 2: &lt;em&gt;Test-Driven Development with Objects&lt;/em&gt;) del libro GOOS, sus autores distinguen entre dos conceptos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;, que “modelan cantidades o mediciones inmutables” (piensa en &lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;Value Objects&lt;/a&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Objetos&lt;/strong&gt;, que “tienen identidad, pueden cambiar de estado con el tiempo y modelan procesos computacionales”.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cuando en el libro GOOS se usa la palabra “object”, se refieren solamente al segundo concepto.&lt;/p&gt;

&lt;h5 id=&quot;no-uses-dobles-de-prueba-para-simular-valores&quot;&gt;¡No uses dobles de prueba para simular valores!&lt;/h5&gt;

&lt;p&gt;Como su mismo título indica, en la sección &lt;em&gt;Don’t Mock Values&lt;/em&gt; (capítulo 20: &lt;em&gt;Listening to the Tests&lt;/em&gt;) recomiendan no usar dobles de prueba para simular valores en los tests.&lt;/p&gt;

&lt;p&gt;Los autores del GOOS dicen aún más:&lt;/p&gt;

&lt;p&gt;“There’s no point in writing mocks for values (which should be immutable anyway). Just create an instance and use it.” (“No tiene sentido escribir mocks para valores (que de todas formas deberían ser inmutables). Simplemente crea una instancia y úsala.”)&lt;/p&gt;

&lt;p&gt;Esta recomendación por sí sola demuestra que la idea de aislar la clase que estamos probando de todas las clases con las que colabora nunca ha formado parte del estilo mockist.&lt;/p&gt;

&lt;p&gt;Es posible que la confusión existente haya surgido porque ambos conceptos, &lt;strong&gt;valores&lt;/strong&gt; y &lt;strong&gt;objetos&lt;/strong&gt;, se implementan usando la misma construcción de lenguaje en la mayoría de los lenguajes orientados a objetos: &lt;em&gt;la clase&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Hay autores que aún reconociendo la distinción entre &lt;strong&gt;valores&lt;/strong&gt; y &lt;strong&gt;objetos&lt;/strong&gt;, siguen sosteniendo que la clase es la unidad en el estilo mockist de TDD&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. Como acabamos de mostrar dicha afirmación es una contradicción.&lt;/p&gt;

&lt;p&gt;Hay más ideas en el libro GOOS que refutan la falsa creencia de considerar que la clase es la unidad en el estilo mockist de TDD.&lt;/p&gt;

&lt;h4 id=&quot;prueba-2-objetos-internos-frente-a-pares5&quot;&gt;Prueba 2: Objetos Internos frente a Pares&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/h4&gt;

&lt;p&gt;Para los autores del libro GOOS no todos los objetos que colaboran con un objeto son considerados de la misma menera.&lt;/p&gt;

&lt;p&gt;En la sección &lt;em&gt;Internals vs Peers&lt;/em&gt; (capítulo 6: &lt;em&gt;Object-Oriented Style&lt;/em&gt;), distinguen dos tipos de colaboradores:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Pares&lt;/strong&gt; (“verdaderos colaboradores”).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Objetos Internos&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/internals_vs_peers.png&quot; alt=&quot;Internos vs Pares de la charla Mock Roles Not Object States.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Objetos Internos vs Pares de la charla &lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States.&lt;/a&gt;&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Lamentablemente, esta distinción entre &lt;em&gt;objetos internos&lt;/em&gt; y &lt;em&gt;pares&lt;/em&gt; es probablemente uno de los conceptos menos comprendidos del libro.&lt;/p&gt;

&lt;h5 id=&quot;reconociendo-a-los-pares&quot;&gt;Reconociendo a los pares.&lt;/h5&gt;

&lt;p&gt;Los autores del libro GOOS consideran que los pares de un objeto son “objetos con responsabilidades únicas”, es decir, que siguen el &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;principio de responsabilidad única&lt;/a&gt;, y que pueden clasificarse (de manera flexible) en tres tipos de relación.&lt;/p&gt;

&lt;p&gt;Estereotipos de pares:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dependencias&lt;/strong&gt;: servicios que el objeto necesita de su entorno para poder cumplir con sus responsabilidades.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Notificaciones&lt;/strong&gt;: otras partes del sistema que necesitan saber cuando el objeto cambia de estado o realiza una acción.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Ajustes o Políticas&lt;/strong&gt;: objetos que ajustan o adaptan el comportamiento del objeto a las necesidades del sistema (piensa en el &lt;a href=&quot;https://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;Patrón Estrategia&lt;/a&gt;).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cualquier colaborador que no sea un par se consideraría un objetos interno.&lt;/p&gt;

&lt;p&gt;Ellos solo consideran estos estereotipos como heurísticas para ayudarnos a pensar en el diseño, no como reglas estrictas. 
Más adelante en el libro, en la sección &lt;em&gt;Where Do Objects Come From?&lt;/em&gt; (capítulo 7: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;), explican otras heurísticas que podemos aplicar para descubrir los pares de un objeto: &lt;em&gt;”Breaking Out”&lt;/em&gt;, &lt;em&gt;“Budding Off”&lt;/em&gt; y &lt;em&gt;”Bundling Up”&lt;/em&gt;. 
Hablaremos de estas técnicas en una publicación futura.&lt;/p&gt;

&lt;p&gt;En su charla &lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States&lt;/a&gt;, Freeman y Pryce ofrecen una excelente explicación de los conceptos de &lt;em&gt;objetos internos&lt;/em&gt; y &lt;em&gt;pares&lt;/em&gt; al discutir el test smell &lt;em&gt;“The test exposes internal implementation details of my object”&lt;/em&gt;.&lt;/p&gt;

&lt;h5 id=&quot;no-uses-dobles-de-prueba-para-simular-objetos-internos&quot;&gt;¡No uses dobles de prueba para simular objetos internos!&lt;/h5&gt;

&lt;p&gt;Identificar los pares de un objeto es crucial para minimizar el acoplamiento de los tests a los detalles de implementación, 
ya que los objetos internos no deben ser simulados en los tests:&lt;/p&gt;

&lt;p&gt;“We should [only] mock an object’s peers—its dependencies, notifications, and adjustments […]—but not its internals” (“Deberíamos simular [solamente] los pares de un objeto, sus dependencias, notificaciones y ajustes […], pero no sus objetos internos”) (capítulo 7: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;En nuestros tests solo usaremos dobles de prueba para simular los comportamientos (roles, responsabilidades) de los que depende el comportamiento que estamos probando, 
no las clases de las que depende. Esto está relacionado con la recomendación “mock roles, not objects”, y esos roles en los que dependen un objeto son sus pares.&lt;/p&gt;

&lt;p&gt;En nuestra opinión, los objetos internos no deberían inyectarse desde fuera, sino que deberían instanciarse dentro de los constructores de los objetos a los que pertenecen.&lt;/p&gt;

&lt;p&gt;La razón tanto de no usar dobles de prueba para simular objetos internos, como para instanciar los objetos internos en los constructores de los objetos a los que pertenecen, es evitar que los tests “sepan” que existen, y que así no estén acoplados con ellos.&lt;/p&gt;

&lt;p&gt;Esta es una diferencia importante entre los objetos internos y los pares: los pares tienen comportamientos lo suficientemente interesantes como para ser “conocidos” y documentados en los tests, mientras que los tests ni siquiera “conocen” la existencia de los objetos internos.&lt;/p&gt;

&lt;h2 id=&quot;cuál-es-entonces-la-unidad-en-el-estilo-mockist-de-tdd&quot;&gt;¿Cuál es entonces la unidad en el estilo mockist de TDD?&lt;/h2&gt;

&lt;p&gt;Esperamos, al menos, haber logrado convencerlos de que la clase tampoco es la unidad en el estilo mockist de TDD.&lt;/p&gt;

&lt;p&gt;Entonces, ¿qué se considera como unidad el estilo mockist de TDD?&lt;/p&gt;

&lt;p&gt;Al igual que el estilo clásico de TDD, el estilo mockist de TDD considera &lt;strong&gt;el comportamiento como la unidad&lt;/strong&gt; en los tests unitarios&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. Y, como hemos visto, un comportamiento puede ser implementado por 1 o N clases, pero esto último ya es solamente un detalle de implementación.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;El propósito de esta publicación era mostrar como una idea muy extendida sobre el estilo mockist de TDD es errónea.&lt;/p&gt;

&lt;p&gt;En algunos casos, esta idea errónea proviene de no haber leído o no haber comprendido bien el libro GOOS.&lt;/p&gt;

&lt;p&gt;En otros casos, creemos que, lamentablemente, esta idea de que la clase es la unidad se utiliza como un &lt;a href=&quot;https://es.wikipedia.org/wiki/Hombre_de_paja&quot;&gt;hombre de paja&lt;/a&gt; para criticar el estilo mockist de TDD, culpando al estilo mockist de TDD de todos los problemas de mantenibilidad al usar dobles de prueba que en realidad están asociados a considerar la clase como la unidad.&lt;/p&gt;

&lt;p&gt;Esperamos, que haber desmentido esta idea errónea, pueda facilitar discusiones más racionales sobre los trade-offs del estilo mockist de TDD y también permitir que se aplique de forma más efectiva.&lt;/p&gt;

&lt;h2 id=&quot;la-serie-sobre-tdd-dobles-de-prueba-y-diseño-orientado-a-objetos&quot;&gt;La serie sobre TDD, dobles de prueba y diseño orientado a objetos.&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;La clase no es la unidad en el estilo de TDD de Londres&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/01/isolated-test-algo-diferente-para-personas-diferentes&quot;&gt;¡”Isolated” test significa algo muy diferente para distintas personas!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;,  (aún por traducir).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Quisiera agradecer a &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franiglesias/&quot;&gt;Fran Iglesias Gómez&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; por darme freedback sobre varios borradores de este texto.&lt;/p&gt;

&lt;p&gt;Finalmente, también quisiera agradecer a &lt;a href=&quot;https://www.pexels.com/es-es/@wwarby/&quot;&gt;William Warby&lt;/a&gt; por su foto.&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.manning.com/books/unit-testing&quot;&gt;Unit Testing Principles, Practices, and Patterns&lt;/a&gt;, &lt;a href=&quot;https://enterprisecraftsmanship.com/&quot;&gt;Vladimir Khorikov&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20090807004827/http://msdn.microsoft.com/en-ca/magazine/dd882516.aspx&quot;&gt;Test-Driven Design Using Mocks And Tests To Design Role-Based Objects &lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/%F0%9F%92%BBisaiah-perumalla-8537563/&quot;&gt;Isaiah Perumalla&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://xunitpatterns.com/DOC.html&quot;&gt;Depended-on component (DOC)&lt;/a&gt;, &lt;a href=&quot;http://xunitpatterns.com/gerardmeszaros.html&quot;&gt;Gerard Meszaros&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;,  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon y Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/RoleInterface.html&quot;&gt;Role Interface&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=QponGU3QgUA&quot;&gt;Rookie Mistake - Testing All The Parts&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5GGk9dv8DVs&quot;&gt;Rookie Mistake - Mock Abuse&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://qafoo.com/blog/111_injectables_newables.html&quot;&gt;Injectables vs. Newables&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/tobiasschlitt/&quot;&gt;Tobias Schlitt&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;Test Desiderata 2/12 Tests Should be Structure-Insensitive&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Cuando aislamos una clase de todas las clases con que colabora, los tests resultantes tendrán una sensibilidad a la estructura muy alta, cuando lo ideal sería que los tests sean insensibles a la estructura (ver &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;Test Desiderata 2/12 Tests Should be Structure-Insensitive&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Si aplicamos un &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt;, el test no fallará en ningún momento durante la refactorización, pero esta es más costoso que hacer una refactorización que no afecta a los tests.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Busca en Internet y encontrarás múltiples ejemplos de la idea errónea que estamos desmintiendo en esta publicación.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Esto ocurre en el libro &lt;a href=&quot;https://www.manning.com/books/unit-testing&quot;&gt;Unit Testing Principles, Practices, and Patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Estamos sustantivando el primer significado del adjetivo “par” que es “igual o semejante totalmente” (ver &lt;a href=&quot;https://www.rae.es/drae2001/par&quot;&gt;par en la RAE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Consideramos que es el que más se aproxima a “peer” que significa “a person of a similar age, position, abilities, etc. as others in a group” (ver &lt;a href=&quot;https://dictionary.cambridge.org/dictionary/english/peer&quot;&gt;peer en Cambridge dictionary&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Otra traducción adecuada de los “pares de un objeto” podría ser “los iguales de un objeto”. Mantuvimos “pares” porque se parece más a “peers”.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] Los autores del libro GOOS afirman que debemos “Unit-Test Behavior, Not Methods” (“Probar unitariamente el comportamiento, no los métodos”) (capítulo 5: &lt;em&gt;Maintaining the Test-Driven Cycle&lt;/em&gt;).&lt;/p&gt;

</description>
          <pubDate>2025-09-29T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/09/mockist-tdd-la-clase-no-es-la-unidad</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/09/mockist-tdd-la-clase-no-es-la-unidad</guid>
        </item>
      
    
      
        <item>
          <title>Removing commented-out code</title>
          <description>&lt;p&gt;This post is a translation of the original post in Spanish: &lt;a href=&quot;https://codesai.com/posts/2022/10/eliminando-codigo-comentado&quot;&gt;Eliminando código comentado&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_code&quot;&gt;Dead Code&lt;/a&gt; is a smell classified within the Wake taxonomy&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; under the Unnecessary Complexity category. It usually appears in the form of variables, parameters, fields, code fragments, functions or classes that are no longer executed.&lt;/p&gt;

&lt;p&gt;The problem is that most of the time we are not sure whether a given piece of code is still used or not. Not knowing whether a piece of code is running or not increases our cognitive load because we have to take it into account and understand it, whenever we are making functional changes or fixing bugs. This unnecessarily increases the complexity of a change. To eliminate this complexity, it would be enough to eliminate dead code, but to do that, we must first be able to detect it.&lt;/p&gt;

&lt;p&gt;There are several ways to detect dead code. The most effective ones rely on the use of tools; for example, most IDEs warn about elements that are no longer used. These tools reduce the cost that would otherwise come from having to detect dead code just by reading the code.&lt;/p&gt;

&lt;p&gt;The tools available depend both on the language being used and on the language features employed in the code. In general, we can say that detecting dead code becomes more difficult the more dynamic the features we are using are.&lt;/p&gt;

&lt;p&gt;In this post we will focus on a type of dead code that is perhaps the easiest to detect: &lt;strong&gt;commented-out code&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;problems-with-commented-out-code&quot;&gt;Problems with commented-out code.&lt;/h2&gt;

&lt;p&gt;We often find commented-out code interspersed with the rest of the code. This breaks the reading flow and forces us to make an effort to ignore the commented code. 
If the commented code blocks are large, sometimes we are forced to scroll in order to continue reading.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/large-comment-block.png&quot; alt=&quot;Long block of commented code&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Long block of commented code.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In addition to the increase in cognitive load that any dead code generates, commented-out code can cause confusion when we take into account, whether with the intention of using it in the future or as an aid to understand the current code, because commented-out code quickly becomes outdated.
Removing commented-out code is usually simple: we just delete the comment containing the code, and if removing it leaves a file empty, we delete the file as well&lt;/p&gt;
&lt;h2 id=&quot;common-resistances-to-removing-commented-out-code&quot;&gt;Common resistances to removing commented-out code.&lt;/h2&gt;
&lt;p&gt;One of the arguments we often encounter for not wanting to remove commented-out code is the belief that it will be needed at some point in the future. For example, sometimes people want to keep the code from a previous implementation that is complex to remember.
A more practical way to allow recovery of a previous version of the code without maintaining commented-out code is to rely on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Version_control&quot;&gt;version control system&lt;/a&gt; we use.&lt;/p&gt;

&lt;p&gt;A common argument against this solution is that it is much easier to recover commented-out code than to find a previous version in version control.
Although it is true that finding a previous version in version control is more difficult, this friction is reduced if we improve our ability to navigate the version control history (either through the IDE or via the command line). 
In addition, we should consider two other factors against keeping commented-out code:
Over time, the need to recover code from a previous version becomes increasingly unlikely because the code will diverge more and more from that past version.&lt;/p&gt;

&lt;p&gt;The problem of unnecessary complexity, which will make evolving the code more costly until the commented-out code is removed.&lt;/p&gt;
&lt;h2 id=&quot;automatically-removing-commented-out-code&quot;&gt;Automatically removing commented-out code.&lt;/h2&gt;

&lt;p&gt;If commenting out code has been a widely used team practice for a long time, we can reach a situation where the cost of removing it is high, and we will have no choice but to live with it for some time, during which we will have to opportunistically delete commented-out code while we are delivering functionality.
In such a situation, it may also be useful to explore tools that automatically remove commented-out code. There are multiple tools that could do this work for most languages. One way to narrow down the tool search is to start by understanding our IDE and taking advantage of its features.
For example, we recently applied this strategy of automatic removal of commented-out code for a client working with Java and IntelliJ.
IntelliJ has a code analysis tool that includes different types of inspections. Beyond the analysis itself, the most powerful feature of this tool is that it allows executing actions (“fixes”) on the detected issues.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/run-inspection-menu.png&quot; alt=&quot;Running inspections by name in IntelliJ&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Running inspections by name in IntelliJ.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The specific inspection for detecting commented-out code is &lt;strong&gt;”Commented out code”&lt;/strong&gt;. You can select the analysis scope, apply various filters, and set the minimum number of lines for comments to consider (which can be useful, for example, if we want to start with large blocks of commented-out code).&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/run-commented-out.png&quot; alt=&quot;Options for running the &apos;commented-out code&apos; inspection&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Options for running the &apos;commented-out code&apos; inspection.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Next, we can select the detected elements we want and proceed to apply some of the fixes suggested by the IDE; in this case, we will apply &lt;strong&gt;Delete comment&lt;/strong&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/delete-comments.png&quot; alt=&quot;Proposed fixes to resolve commented-out code&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Proposed fixes to resolve commented-out code.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;After making these changes, run your tests to ensure that the expected behavior has not been altered. Depending on your situation (test coverage, team confidence, etc.), it may also be useful to verify that the deletion was done correctly by reviewing the resulting code. However, if there are many changes, this can be very labor-intensive. In that case, you could plan the deletion in multiple phases, dividing it by file types, packages, or another division criterion that suits your situation.&lt;/p&gt;

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

&lt;p&gt;We have seen that commented-out code is one of the forms in which the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_code&quot;&gt;Dead Code&lt;/a&gt; smell appears, and how this smell unnecessarily increases the complexity of our code.&lt;/p&gt;

&lt;p&gt;We have presented the most common arguments (in our experience) for resisting the removal of commented-out code, and provided counterarguments to refute them.&lt;/p&gt;

&lt;p&gt;Finally, when working with a codebase full of commented-out code, we have recommended an alternative to removing commented-out code through opportunistic refactoring: exploring the tools at your disposal to see if they offer functionalities to automatically remove dead code. This will allow you to eliminate a larger amount of commented-out code at a manageable cost.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;
&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] You can read about Wake taxonomy and others in our post &lt;a href=&quot;https://codesai.com/posts/2022/11/code-smells-taxonomies-and-catalogs-english&quot;&gt;On code smells catalogues and taxonomies&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2025-09-08T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/09/removing-commented-out-code</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/09/removing-commented-out-code</guid>
        </item>
      
    
      
        <item>
          <title>Segregating a test builder applying the curiously recurring template pattern</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;In this post we show the evolution of a test builder to support several parallel changes we made to evolve the design of the production code. 
This evolution degraded the design of the test builder until a point where we felt the need to refactor it to avoid potential problems.&lt;/p&gt;

&lt;h2 id=&quot;the-evolution-of-the-test-builder&quot;&gt;The evolution of the test builder.&lt;/h2&gt;

&lt;h3 id=&quot;step-1&quot;&gt;Step 1.&lt;/h3&gt;

&lt;p&gt;Initially, we had some data representing a claim. These data were what we call &lt;strong&gt;“travelling data”&lt;/strong&gt;, which are data that are taken by the application from one of its edges to another without being transformed or having any influence on the execution flow or logic of the application. So, we kept them in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_transfer_object&quot;&gt;DTO&lt;/a&gt;, called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt;, and that’s what the test builder initially built (we elided some details for the sake of brevity):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/607a527a0e18014134ccc444fc14ab46.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;step-2&quot;&gt;Step 2.&lt;/h3&gt;

&lt;p&gt;Later in the development of the application, some requirements made it necessary to introduce new logic having to do with some claim data. So we introduced a domain object, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt;, which we mapped from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt; to encapsulate that logic.&lt;/p&gt;

&lt;p&gt;Since they held nearly the same information, a slight change to our test builder allowed us to do the required parallel change smoothly. This the resulting code of the test builder (we elided some details for the sake of brevity):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/87c1a0b857420e9a25dc12b711421ad2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the two methods &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildData()&lt;/code&gt; that are used to create different objects from the same data. They were very handy to smoothly migrate our tests to the new design.&lt;/p&gt;

&lt;h3 id=&quot;step-3&quot;&gt;Step 3.&lt;/h3&gt;

&lt;p&gt;Finally, a new change required to introduce two different states for a claim. So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim&lt;/code&gt; became an interface implemented by two new classes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We tweaked again the test builder in order to support the refactoring to this new design (we elided some details for the sake of brevity):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c5aa019fd8581487a7a5ab75b98d68b2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This test builder can build instances of three classes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt; (the DTO), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The building of each kind of object shared most of the setters. However, there was a setter, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withCompany&lt;/code&gt;, that was only used to build &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; objects, and two other setters, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withOpeningListener&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withReferenceInCompany&lt;/code&gt;, that were only used to build &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt; objects. This was confusing.&lt;/p&gt;

&lt;p&gt;Notice also the conditional in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;This test builder had too many responsibilities, so after finishing refactoring the production code, we needed to refactor it.&lt;/p&gt;

&lt;p&gt;We wanted to split it into three test builders, one for each kind of object: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;, while still reusing as much code as possible.&lt;/p&gt;

&lt;p&gt;We didn’t know the best approach to do this, so, outside of work hours, I explored refactoring it to various alternative designs to both solve the problem, and learn and practice.&lt;/p&gt;

&lt;h2 id=&quot;two-failed-designs&quot;&gt;Two failed designs.&lt;/h2&gt;

&lt;h3 id=&quot;approach-1-segregating-interfaces&quot;&gt;Approach 1: Segregating interfaces.&lt;/h3&gt;

&lt;p&gt;First, I tried segregating interfaces and having a test builder that implemented all of them.&lt;/p&gt;

&lt;p&gt;This design allowed reusing most of the setters and avoided the possibility of using a method that was not involved in creating a given kind of object. For instance, it avoided being able to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withOpeningListener&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;withReferenceInCompany&lt;/code&gt; when not building an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the negative side, I couldn’t call the setters in any order anymore which made the experience of using the fluid interface less smooth.&lt;/p&gt;

&lt;h3 id=&quot;approach-2-using-inheritance&quot;&gt;Approach 2: Using inheritance.&lt;/h3&gt;

&lt;p&gt;I created an abstract &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; containing all the common fields and setters, and some abstract methods (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildData&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then I made three concrete builders that inherited from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaimBuilder&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaimBuilder&lt;/code&gt; that created instances of  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaim&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaim&lt;/code&gt;, respectively.&lt;/p&gt;

&lt;p&gt;This design also reused most of the setters and avoided the possibility of using setters that were not involved in creating a given kind of object.&lt;/p&gt;

&lt;p&gt;In order to be able to call the setters in any order, the method that created the instances had to be declared as an abstract public method in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt;, and this meant two problems:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The method that created the instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData&lt;/code&gt; could not be called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt;. This is because, in Java, &lt;a href=&quot;https://www.baeldung.com/java-method-overload-override#bd-method-overloading&quot;&gt;method overloading&lt;/a&gt; is not allowed for methods that differ only in their return types (see &lt;a href=&quot;https://www.baeldung.com/java-method-overload-override#bd-2-arguments-of-different-types&quot;&gt;Overloading methods with arguments of different types&lt;/a&gt;). So, I couldn’t have two methods with the following signatures: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData build()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim build()&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Because of the first problem. I had to declare two abstract public methods in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimData buildData()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claim build()&lt;/code&gt;. This meant that each derived builder had both methods in their interface.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;finally-a-successful-design&quot;&gt;Finally a successful design!&lt;/h2&gt;

&lt;p&gt;I thought: &lt;em&gt;“if only the return type of the setters was different for each type of builder”&lt;/em&gt;, and it came to me that the answer might be using &lt;a href=&quot;https://en.wikipedia.org/wiki/Generics_in_Java&quot;&gt;generics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I created an initial version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; using generics to be able to use different return types for the setters:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d4d6890af072cfbf11a4e469284349e5.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I elided some details for the sake of brevity, but you can still notice in the setters how they return the generic type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another improvement over the previous design was that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildData&lt;/code&gt; became protected.&lt;/p&gt;

&lt;p&gt;The casts to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; in the returns of the setters are unchecked which produces an &lt;a href=&quot;https://www.baeldung.com/java-warning-unchecked-cast&quot;&gt;unchecked-cast warning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; I used it to create the following three derived builders:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClaimDataBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a7b3ca583040547457e510397b9d150e.js&quot;&gt;&lt;/script&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToOpenClaimBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/396bb57f884025dabeec6c72a1ecbec2.js&quot;&gt;&lt;/script&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OpenButNotNotifiedClaimBuilder&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3cf143e672aed604aefa083034c94541.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how each of the concrete builders is specifying to itself the type used in the generic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; base class.&lt;/p&gt;

&lt;p&gt;This enables our previous stated desire: &lt;em&gt;“if only the return type of the setters was different for each type of builder”&lt;/em&gt;. Now, the setters of each concrete builder return its own type, which solves all the problems I faced with the two previous designs.&lt;/p&gt;

&lt;p&gt;Each derived builder defines methods that are only related to what it builds.&lt;/p&gt;

&lt;p&gt;I can call the methods in any order, and only the methods involved in building instances of a given class are available.&lt;/p&gt;

&lt;p&gt;Finally, I improved &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; &lt;a href=&quot;https://www.baeldung.com/java-generics#bd-1-bounded-generics&quot;&gt;bounding&lt;/a&gt; the kind of types that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claimbuilder&lt;/code&gt; can be specified with, so that only types that are derived from itself can be used.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/eb6e5ed25ccdea2421565b6981ca488e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how I &lt;a href=&quot;https://www.baeldung.com/java-generics#bd-1-bounded-generics&quot;&gt;bounded&lt;/a&gt; the generic in the class declaration:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class ClaimBuilder&amp;lt;T extends ClaimBuilder&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It turns out that what I had done is known as the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;Curiously recurring template pattern&lt;/a&gt; (CRTP), also known as &lt;a href=&quot;https://www.cs.utexas.edu/~wcook/papers/FBound89/CookFBound89.pdf&quot;&gt;F-bound polymorphism&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If I had known the pattern (its intent, applicability and consequences), I could have gotten to this design much faster… 😅
I’ll do it next time.&lt;/p&gt;

&lt;p&gt;Finally, I also added a method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self&lt;/code&gt; to encapsulate the unchecked cast to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; (advised by IntelliJ’s AI assistant), and annotated it to suppress the warning.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;This post chronicles the evolution of a test builder through multiple stages of development, highlighting how the initial simple design gradually became more complex as new requirements emerged. From a basic DTO builder for claim data, it evolved to also create a claim domain object, and eventually to support the creation of multiple claim states. This evolution led to a test builder with too many responsibilities.&lt;/p&gt;

&lt;p&gt;I refactored the test builder to several alternative designs. The first approach using interface segregation compromised the fluid interface’s flexibility, while the second one using inheritance ran into Java’s type system limitations with method overloading.&lt;/p&gt;

&lt;p&gt;Those failed attempts led me to explore a more sophisticated approach using generics, that unknowingly applied the &lt;a href=&quot;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;Curiously recurring template pattern&lt;/a&gt;, in which a class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt; derives from a generic class instantiation using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt; itself as a type argument.&lt;/p&gt;

&lt;p&gt;The resulting design addressed my requirements because it enabled chaining setter methods in any order while restricting available methods to only those relevant for building each specific claim type.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank my colleague &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for giving me feedback about this post.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.linkedin.com/in/carlosmiguelseco/&quot;&gt;Carlos Miguel Seco&lt;/a&gt; for giving us the opportunity to work with him on a very interesting project.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://pixabay.com/users/mariofcomeh61-17077957/&quot;&gt;mariofcomeh61&lt;/a&gt; for the photo.&lt;/p&gt;

</description>
          <pubDate>2025-07-29T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/segregating-test-builder</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/segregating-test-builder</guid>
        </item>
      
    
      
        <item>
          <title>Convirtiendo tests no paramétricos en paramétricos con la IA (e intentando generar ejemplos)</title>
          <description>&lt;h2 id=&quot;introdución&quot;&gt;Introdución.&lt;/h2&gt;

&lt;p&gt;Una de las cosas para las que suelo usar la IA con muy buenos resultados, es para pasar un test de no paramétrico a paramétrico.&lt;/p&gt;

&lt;p&gt;Suelo introducir tests paramétricos en muchos contextos diferentes para quitar duplicación y subir el nivel de abstracción de la descripción del test, de forma que describa más directamente una regla de negocio o un comportamiento.&lt;/p&gt;

&lt;h2 id=&quot;ejemplo-1&quot;&gt;Ejemplo 1.&lt;/h2&gt;

&lt;p&gt;Veamos un ejemplo de cómo el &lt;a href=&quot;https://www.jetbrains.com/help/idea/ai-assistant-in-jetbrains-ides.html&quot;&gt;asistente de IA de IntelliJ&lt;/a&gt; me permite hacer este cambio muy rápidamente:&lt;/p&gt;

&lt;p&gt;Empecé seleccionando el test que quería cambiar y escogí la opción de abrir un nuevo chat de IA con la selección.&lt;/p&gt;

&lt;p&gt;Una vez en el chat le pedí que me conviertiera el test seleccionado en un test paramétrico:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;User: 
&lt;script src=&quot;https://gist.github.com/trikitrok/466882f41990a1d67d1be76203392552.js&quot;&gt;&lt;/script&gt;
convert to parametric test passing as parameter a word and an expectedKey,
in this case they are “A” and “a”, respectively&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El asistente me lo hizo sin problema:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Assistant: 
I’ll help you convert the test to a parametric test using Jest’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.each&lt;/code&gt;. Here’s the converted test:
&lt;script src=&quot;https://gist.github.com/trikitrok/0bb5ae45330543030ed5ed6d2c8b1f91.js&quot;&gt;&lt;/script&gt;
This test uses Jest’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.each&lt;/code&gt; which allows you to: [&lt;em&gt;… explica un montón de cosas sobre Jest, los tests paramétricos, cómo funciona todo, etc.&lt;/em&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El código generado tenía buena pinta por lo que le dije que lo insertara en el lugar donde tenía el cursor (&lt;em&gt;caret&lt;/em&gt;), y después ejecuté los tests.&lt;/p&gt;

&lt;p&gt;Como los tests pasaron, hice commit. Si los tests no hubieran pasado, hubiera hecho una “retirada honrosa”&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. Debo decir que esto último aún no me ha pasado al transformar tests a parámetricos.&lt;/p&gt;

&lt;p&gt;Después de tener el test paramétrico, como el motivo para pasar a tests paramétricos era que quería triangular sin generar duplicación, le pedí al asistente que me generase un ejemplo más:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;User: 
generate another example&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Assistant: 
Based on the domain of the application (text processing with case insensitivity), I’ll generate one more test case that cover a different scenario:
&lt;script src=&quot;https://gist.github.com/trikitrok/5fdac0a5ad693be4217a0f77f7936ef4.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Además el asistente me propuso una implementación obvia del código de producción, (que yo tenía “fakeado” para pasar el primer ejemplo a verde), que hacía que ambos tests pasaran:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;script src=&quot;https://gist.github.com/trikitrok/52d115fde4d55e28642b7a5b8de4bce0.js&quot;&gt;&lt;/script&gt;

&lt;/blockquote&gt;

&lt;p&gt;Si el motivo para pasar a tests paramétricos hubiese sido que quería añadir más casos de tests para un código ya escrito (es decir, fuera de un flujo de TDD), también se le podría pedir que genere varios ejemplos más. En este caso, el asistente no sólo los genera, sino que además explica qué criterios usó para elegir cada ejemplo.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Assistant: 
Based on the domain of the application (text processing with case insensitivity), I’ll generate more test cases that cover different scenarios:
&lt;script src=&quot;https://gist.github.com/trikitrok/099a90329d42ec7cb0891c16bba23e7d.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

  &lt;p&gt;These test cases cover:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Single uppercase letter&lt;/li&gt;
    &lt;li&gt;Capitalized word&lt;/li&gt;
    &lt;li&gt;All uppercase word&lt;/li&gt;
    &lt;li&gt;Mixed case word&lt;/li&gt;
    &lt;li&gt;Alternating case&lt;/li&gt;
    &lt;li&gt;Word from the domain example&lt;/li&gt;
    &lt;li&gt;Alphanumeric string&lt;/li&gt;
    &lt;li&gt;String with whitespace&lt;/li&gt;
    &lt;li&gt;String with special characters&lt;/li&gt;
    &lt;li&gt;String with non-ASCII characters&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Each test case verifies that the input string is converted to its lowercase equivalent, which is the expected behavior of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CaseInsensitiveWordToKey&lt;/code&gt; class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En este caso concreto, muchos de los ejemplos no eran necesarios y sólo introducían ruido, por lo que eliminé la mayoría de ellos.&lt;/p&gt;

&lt;p&gt;La generación de nuevos ejemplos con la IA no es algo que vaya demasiado bien, y, dependiendo del contexto, puede generar muchos ejemplos redundantes.&lt;/p&gt;

&lt;p&gt;Encuentro que conociendo conceptos como &lt;a href=&quot;https://en.wikipedia.org/wiki/Equivalence_partitioning&quot;&gt;particiones de equivalencia&lt;/a&gt; y &lt;a href=&quot;https://en.wikipedia.org/wiki/Boundary-value_analysis&quot;&gt;análisis de valores de frontera&lt;/a&gt; puedo generar yo mismo ejemplos más significativos de manera más eficiente (o guiar a la IA para que lo haga mejor)&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En el siguiente ejemplo veremos otro tipo de problema que se puede dar cuando generamos ejemplos para tests con la IA.&lt;/p&gt;

&lt;h2 id=&quot;ejemplo-2&quot;&gt;Ejemplo 2.&lt;/h2&gt;

&lt;p&gt;Hasta ahora hemos visto un caso muy sencillo. El siguiente ejemplo en C# y &lt;a href=&quot;https://nunit.org/&quot;&gt;Nunit&lt;/a&gt; es algo más complicado.&lt;/p&gt;

&lt;p&gt;En este ejemplo estaba probando el asistente de IA para añadir tests a un código ya existente que validaba los datos personales de un usuario para decidir si abrirle una cuenta en el sistema o no.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;User:
&lt;script src=&quot;https://gist.github.com/trikitrok/c9d18e14eb62c4f217ec0b970b62f2fc.js&quot;&gt;&lt;/script&gt;
pass to parametric test passing a validDNI, add several examples, don’t add what comments [&lt;em&gt;la última parte del prompt me evita las, al menos para mí, molestas líneas de comentarios con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Given&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;When&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Then&lt;/code&gt;, (o la versión alternativa de comentarios con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Arrange&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Act&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Assert&lt;/code&gt;)&lt;/em&gt;]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Assistant:
Based on the code, I’ll help convert the test to use parametric testing with multiple valid DNI examples. Looking at the existing test structure and other tests in the file, here’s how we can modify it:
&lt;script src=&quot;https://gist.github.com/trikitrok/ccaca9fcc10232a564d95cc652a2f7e7.js&quot;&gt;&lt;/script&gt;
I’ve added multiple test cases with valid Spanish DNI formats. Each DNI follows the pattern of 8 digits followed by a control letter. You can remove the original non-parametric test since this parametric version covers the same functionality with more test cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Después de insertar este test donde tenía el cursor, lancé los tests y resultó que dos de los DNI “válidos” generados no eran válidos según el código de producción: “72841539P” y “23456789T”.&lt;/p&gt;

&lt;p&gt;Como estábamos testeando un código a posteriori, en ese momento no podíamos saber si estos fallos se debían a que los DNI generados como válidos por la IA eran realmente inválidos, es decir la IA los había “&lt;a href=&quot;https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)&quot;&gt;alucinado&lt;/a&gt;”, o si, por el contrario, los ejemplos generados por la IA eran correctos y habíamos descubierto algún error en el código de producción.&lt;/p&gt;

&lt;p&gt;Para averiguar cuál de las dos razones estaba provocando los fallos utilicé dos herramientas de validación online&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; y resultó que los dos valores generados por la IA que hacían fallar el test eran realmente inválidos. Esto quería decir que la IA se había equivocado.&lt;/p&gt;

&lt;p&gt;Como aproveché estos ejemplos de DNI inválido alucinados para el test paramétrico &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cannot_Create_User_Account_When_Invalid_Dni_Is_Provided&lt;/code&gt;, la alucinación no me fue tan mal 😅.&lt;/p&gt;

&lt;p&gt;En cualquier caso, este ejemplo debería servir como recordatorio de que hay que tener mucho cuidado al generar casos de test directamente con una IA porque puede alucinar y generarnos ejemplos erróneos. Tengo que decir que en este experimento de añadir tests a posteriori a la validación de DNI, NIE y CIF la IA se equivocó (alucinó) muchísimo.&lt;/p&gt;

&lt;p&gt;Nuestro conocimiento sobre el dominio, o, como en este caso, disponer de herramientas de validación alternativas, nos puede ayudar a evaluar si los ejemplos generados por la IA son correctos.&lt;/p&gt;

&lt;p&gt;Una alternativa más lenta, en este caso, hubiera sido generar los ejemplos nosotros mismos a partir de una especificación.&lt;/p&gt;

&lt;p&gt;Otra alternativa, aún más interesante, hubiera sido usar una técnica de desarrollo como TDD para desarrollar el código, que nos permite generar los tests y el código de producción de forma incremental, y nos puede dar más confianza de que estamos convergiendo hacia una solución que realmente funciona.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;Hemos mostrado en diferentes contextos como un asistente de IA nos puede ser muy útil para pasar un test de no paramétrico a paramétrico de forma muy eficiente.&lt;/p&gt;

&lt;p&gt;También hemos visto cómo la generación de ejemplos de test con IA puede ser problemática debido a:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;la generación de casos de test erróneos debidos a “alucinaciones”.&lt;/li&gt;
  &lt;li&gt;la generación de casos de test redundantes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Conocer técnicas de testing&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; como &lt;a href=&quot;https://en.wikipedia.org/wiki/Equivalence_partitioning&quot;&gt;particiones de equivalencia&lt;/a&gt; y &lt;a href=&quot;https://en.wikipedia.org/wiki/Boundary-value_analysis&quot;&gt;análisis de valores de frontera&lt;/a&gt; puede ayudarnos, respectivamente, a eliminar casos de test redundantes y a añadir casos de test relevantes que nos falten.&lt;/p&gt;

&lt;p&gt;Sin embargo, generar casos de tests erróneos debido a alucinaciones es un problema más fundamental, y no les quedará otra que revisar muy bien los tests generados por la IA. 
Por ahora, sólo podemos recomendarles que tengan mucha precaución si usan la IA para generar tests a posteriori.&lt;/p&gt;

&lt;p&gt;Creemos que hay otras técnicas existentes que les pueden dar mejor resultado:&lt;/p&gt;

&lt;p&gt;a. Si están testeando código legado, técnicas como &lt;a href=&quot;https://michaelfeathers.silvrback.com/characterization-testing&quot;&gt;characterization testing&lt;/a&gt; o &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;sampling + golden master&lt;/a&gt; (o su mejora con herramientas, &lt;a href=&quot;https://approvaltests.com/&quot;&gt;approval testing&lt;/a&gt;) en combinación con &lt;a href=&quot;https://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;mutation testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;b. Si están testeando código a posteriori que acaban de escribir, y que por tanto no es código legado porque aún no da valor a ningún usuario, lo indicado sería escribir tests que chequeen que ese código hace lo que debería hacer, es decir, que chequeen que el código cumple con su especificación (&lt;a href=&quot;https://www.effective-software-testing.com/it-is-not-about-following-a-recipe&quot;&gt;specification-based testing&lt;/a&gt;). A continuación, podrían completar y mejorar los tests resultantes aplicando &lt;a href=&quot;https://en.wikipedia.org/wiki/White-box_testing&quot;&gt;structural testing&lt;/a&gt; y/o &lt;a href=&quot;https://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;mutation testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En ambos casos podríamos usar la IA como asistente para facilitarnos parte del trabajo.&lt;/p&gt;

&lt;p&gt;¿Están usando IAs para generar tests? ¿Cómo están siendo sus experiencias?&lt;/p&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Me gustaría darle las gracias a &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; por revisar y darme feedback sobre el primer borrador de este post.&lt;/p&gt;

&lt;p&gt;También me gustaría agradecer a &lt;a href=&quot;https://www.pexels.com/es-es/@olia-danilevich/&quot;&gt;Olia Danilevich&lt;/a&gt; por la foto suya que usamos para este post.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] La “retirada honrosa” (“honourable retreat”) es una de las técnicas descritas por &lt;a href=&quot;https://www.industriallogic.com/people/joshua/&quot;&gt;Joshua Kerievsky&lt;/a&gt; en su charla &lt;a href=&quot;https://www.infoq.com/presentations/The-Limited-Red-Society/&quot;&gt;The limited red society&lt;/a&gt; en la que introduce y demuestra tres técnicas para reducir el tiempo que tus tests están en rojo mientras refactorizas: “honourable retreat”, “narrowed change” y “parallel change”. En nuestra formación &lt;a href=&quot;https://codesai.com/cursos/refactoring/&quot;&gt;Code Smells &amp;amp; Refactoring&lt;/a&gt; profundizamos en ellas y las practicamos en varias katas.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Profundizamos en estos conceptos y los practicamos en nuestras formaciones &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt;, &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;TDD&lt;/a&gt; y &lt;a href=&quot;https://codesai.com/cursos/testing-techniques/&quot;&gt;Técnicas de Testing para desarrolladores&lt;/a&gt;, desde puntos de vista liegeramente diferentes.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Usé &lt;a href=&quot;https://andresledo.es/herramientas/validar-dni-nif-cif-online/&quot;&gt;https://andresledo.es/herramientas/validar-dni-nif-cif-online/&lt;/a&gt; y &lt;a href=&quot;https://testingdatagenerator.com/doi.html&quot;&gt;https://testingdatagenerator.com/doi.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] En este post hemos mencionado varias técnicas de testing que pueden ser muy útiles tanto si trabajamos con una IA como si no.&lt;/p&gt;

&lt;p&gt;La siguiente tabla muestra en cuáles de nuestras formaciones se explican y practican en profundidad estas técnicas de testing (el énfasis y el punto de vista pueden variar un poco según el curso).&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Técnica / Formación&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://codesai.com/cursos/testing-techniques/&quot;&gt;Técnicas de Testing para desarrolladores&lt;/a&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;TDD&lt;/a&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Particiones de equivalencia&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Análisis de valores de frontera&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Characterization testing&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sampling + Golden Master&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Approval testing&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mutation testing&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Specification-based testing&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Structural testing&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

</description>
          <pubDate>2025-07-18T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/convertir-tests-en-parametricos-con-IA</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/convertir-tests-en-parametricos-con-IA</guid>
        </item>
      
    
      
        <item>
          <title>Using prompt patterns to enhance how you learn about prompt patterns</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;I’m learning about prompt engineering which is the practice of designing effective inputs (prompts) to guide AI models toward producing accurate, useful, or creative outputs.&lt;/p&gt;

&lt;p&gt;To that purpose I’m free auditing &lt;a href=&quot;https://www.coursera.org/&quot;&gt;Coursera&lt;/a&gt;’s &lt;a href=&quot;https://www.coursera.org/learn/prompt-engineering/home/welcome&quot;&gt;Prompt Engineering for ChatGPT&lt;/a&gt; course by &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As part of this course, I read the paper &lt;a href=&quot;https://arxiv.org/abs/2302.11382&quot;&gt;A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT&lt;/a&gt; which presents a structured approach to prompt engineering using patterns, much like design patterns in software engineering.&lt;/p&gt;

&lt;p&gt;The paper identifies 16 prompt patterns, grouped into 5 main categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Input Semantics&lt;/strong&gt;: &lt;em&gt;Meta Language Creation&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Output Customization&lt;/strong&gt;: &lt;em&gt;Output Automater&lt;/em&gt;, &lt;em&gt;Persona&lt;/em&gt;, &lt;em&gt;Visualization Generator&lt;/em&gt;, &lt;em&gt;Recipe&lt;/em&gt; and &lt;em&gt;Template&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Error Identification&lt;/strong&gt;: &lt;em&gt;Fact Check List&lt;/em&gt; and &lt;em&gt;Reflection&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Prompt Improvement&lt;/strong&gt;: &lt;em&gt;Question Refinement&lt;/em&gt;, &lt;em&gt;Alternative Approaches&lt;/em&gt;, &lt;em&gt;Cognitive Verifier&lt;/em&gt; and &lt;em&gt;Refusal Breaker&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Interaction&lt;/strong&gt;: &lt;em&gt;Flipped Interaction&lt;/em&gt;, &lt;em&gt;Game Play&lt;/em&gt; and &lt;em&gt;Infinite Generation&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Context Control&lt;/strong&gt;: &lt;em&gt;Context Manager&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to the authors, “prompt patterns are essential to effective prompt engineering” because “[they] document successful approaches for systematically engineering different output and interaction goals when working with conversational LLMs.”&lt;/p&gt;

&lt;h2 id=&quot;using-prompting-patterns-to-create-retrieval-practice-exercises-about-prompting-patterns&quot;&gt;Using prompting patterns to create retrieval practice exercises about prompting patterns.&lt;/h2&gt;

&lt;p&gt;Previously I had audited another related Coursera course, &lt;a href=&quot;https://www.coursera.org/learn/learning-chatgpt&quot;&gt;Accelerate Your Learning with ChatGPT&lt;/a&gt; by &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Barbara_Oakley&quot;&gt;Barbara Oakley&lt;/a&gt; which explores how to enhance your learning using generative AI tools, integrating insights from neuroscience, cognitive psychology, and AI&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://psychology.ucsd.edu/undergraduate-program/undergraduate-resources/academic-writing-resources/effective-studying/retrieval-practice.html&quot;&gt;Retrieval practice&lt;/a&gt;, which involves recalling to-be-remembered information from memory, is one of the most effective learning methods discovered to date. This technique works especially well when you subsequently check your answers against your study materials. According to &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Barbara_Oakley&quot;&gt;Barbara Oakley&lt;/a&gt;, generative AI can be a great way to create &lt;em&gt;retrieval practice&lt;/em&gt; exercises.&lt;/p&gt;

&lt;p&gt;After reading the paper, I wanted to do some &lt;em&gt;retrieval practice&lt;/em&gt; to learn the contents in the paper more deeply, so I decided to use what I remembered from reading the paper to prompt ChatGpt to create a retrieval practice game. Doing this, I was not only applying what I had read about prompting patterns (an example of &lt;em&gt;retrieval practice&lt;/em&gt; in itself), but also, taking advantage of generative AI to get more opportunities to do &lt;em&gt;retrieval practice&lt;/em&gt; and receive immediate feedback on my attempts.&lt;/p&gt;

&lt;h3 id=&quot;creating-and-playing-a-prompt-pattern-learning-game&quot;&gt;Creating and playing a prompt pattern learning game.&lt;/h3&gt;

&lt;p&gt;This is part of my raw interaction with ChatGPt, which shows how I prompted it to create a prompt pattern learning game, and how I did &lt;em&gt;retrieval practice&lt;/em&gt; by plaing the game (I’ve added some thoughts and comments that were not part of the interaction between square brackets):&lt;/p&gt;

&lt;p&gt;After uploading the &lt;a href=&quot;https://arxiv.org/abs/2302.11382&quot;&gt;A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT&lt;/a&gt; paper PDF on ChatGpt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Me: &lt;em&gt;If you were this PDF how would you create a game to help me learn about you?&lt;/em&gt; [I was informally using the &lt;strong&gt;Persona&lt;/strong&gt; and the &lt;strong&gt;Game Play&lt;/strong&gt; patterns from the paper]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/e88887269e2339bf2cd92aa371997df2.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Me: &lt;em&gt;Guess the Pattern&lt;/em&gt; [I started with the multiple-choice quiz because I think it’s much easier than the other kind of exercises in the game.]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/baed5ae8b960bcf03254a7caa7ce26f0.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Me: &lt;em&gt;b&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/86f43503ba4c656d485b21b7fd1f9f59.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ChatGpt gave me feedback about my answer and explained a bit why it was right. Then it asked me a new question.&lt;/p&gt;

&lt;p&gt;For the sake of brevity, I’ll skip a big part of my retrieval practice, and jump to a moment where, after having done several multiple-choice quizzes, I changed to a different kind of exercise that I considered a bit more challenging:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/ca03bec68e35f455b5568dd533784b67.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Me: &lt;em&gt;Fix the Prompt (remind me the mechanics of the quest, at the beginning, please)&lt;/em&gt; [I choose the &lt;em&gt;Fix the Prompt&lt;/em&gt; challenge, I also ask ChatGpt to remind its mechanics because I had forgotten them after a lot of &lt;em&gt;Guess the Pattern&lt;/em&gt; exercises.]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/253d12a3a553b46fcc34fafaefb9f31c.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Me: [After a while, because, at least for me, analyzing and creating is much harder than the pattern matching required in a multiple-choice quiz.]
&lt;script src=&quot;https://gist.github.com/trikitrok/6b504b7f4d9831033a42573418087032.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;ChatGpt:
&lt;script src=&quot;https://gist.github.com/trikitrok/65427baab79ac0495c9688ca012daa95.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice how ChatGpt’s feedback was much more detailed in this last exercise. It told me that my prompt worked and that the patterns that I was trying to use were there, and how explicit they were (which is where the prompt could have been better). Then, it suggested an improved version of my prompt which is great feedback for my learning. Finally, it prompted me to keep on playing.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h2&gt;

&lt;p&gt;In this post, we’ve shared a bit of our journey exploring prompt engineering, demonstrating a practical application of this technique. It began with insights from a Coursera course and a key research paper that introduced us to several useful prompt patterns which provide structured approaches for enhancing interactions with AI models.&lt;/p&gt;

&lt;p&gt;To deepen our understanding of these concepts, we turned to retrieval practice, a proven learning technique that involves actively recalling information. We decided to put our incipient knowledge about prompt patterns to practical use by working with ChatGPT to create an interactive learning game, which allowed us to both apply and reinforce what we had learned about prompt patterns.&lt;/p&gt;

&lt;p&gt;We showed you part of the interactive exercises that ChatGPT prompted us to solve. Through those exercises, we progressed from basic quizzes to more challenging exercises, with ChatGPT providing us valuable feedback to deepen our understanding at each step.&lt;/p&gt;

&lt;p&gt;We think that this application of the &lt;strong&gt;Persona&lt;/strong&gt; and &lt;strong&gt;Game Play&lt;/strong&gt; patterns might be used for enhancing your learning of many different topics. We encourage you to try them. We’d love to hear about your experiences!&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/2302.11382&quot;&gt;A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT&lt;/a&gt;, &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.coursera.org/learn/prompt-engineering/home/welcome&quot;&gt;Prompt Engineering for ChatGPT&lt;/a&gt; course materials, &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.coursera.org/learn/learning-chatgpt&quot;&gt;Accelerate Your Learning with ChatGPT&lt;/a&gt; course materials, &lt;a href=&quot;https://engineering.vanderbilt.edu/bio/?pid=jules-white&quot;&gt;Jules White&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Barbara_Oakley&quot;&gt;Barbara Oakley&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://psychology.ucsd.edu/undergraduate-program/undergraduate-resources/academic-writing-resources/effective-studying/retrieval-practice.html&quot;&gt;Retrieval Practice&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.promptingguide.ai/&quot;&gt;Prompt Engineering Guide&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Use this prompt to ask to some generative AI tool about the course:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What is the course “Accelerate Your Learning with ChatGPT” by Barbara Oakley and Jules White about?&lt;/p&gt;
&lt;/blockquote&gt;

</description>
          <pubDate>2025-07-14T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/prompt-patterns-to-learn-prompt-patterns</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/prompt-patterns-to-learn-prompt-patterns</guid>
        </item>
      
    
      
        <item>
          <title>Mejorar nuestros rojos</title>
          <description>&lt;p&gt;Este post es una mejora, actualización y traducción del post original en inglés: &lt;a href=&quot;https://codesai.com/posts/2018/06/improving-your-reds&quot;&gt;Improve your reds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;“Mejorar nuestros rojos” es un sencillo consejo que dan &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; y &lt;a href=&quot;http://www.natpryce.com/&quot;&gt;Nat Pryce&lt;/a&gt; en su maravilloso libro &lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se trata de una pequeña variación del ciclo de TDD en la que observamos los mensajes de error que obtenemos cuando un test falla y nos preguntamos si la información que nos da haría más sencillo diagnosticar el origen del problema en caso de que ese error apareciera en el futuro como un error de regresión. Si la respuesta es que no, deberíamos mejorar el mensaje de error antes de hacer que el test pase a verde.&lt;/p&gt;

&lt;figure style=&quot;height:60%; width:60%;&quot;&gt;
	&lt;img src=&quot;/assets/feedback-on-diagnostics.svg&quot; alt=&quot;Variación del ciclo de TDD: mejorar el feedback para diagnosticar problemas mejor.&quot; /&gt;
	&lt;figcaption&gt;
  	De Growing Object-Oriented Software de Nat Pryce y Steve Freeman.
	&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Invertir un poquito de tiempo en mejorar nuestros rojos es una manera muy sencilla de aumentar nuestra productividad futura y la de nuestros compañeros. En caso de que se produzca ese error de regresión, mejorar nuestros rojos nos ayudará mucho porque entre más claro sea el mensaje de error más contexto tendremos para poder arreglar el problema eficientemente.&lt;/p&gt;

&lt;p&gt;Además en el momento en que estamos haciendo TDD es cuando más contexto tenemos para poder crear un buen mensaje de error porque el problema está aún fresco en nuestra cabeza. A lo que se suma que, en la mayoría de ocasiones, mejorar nuestros rojos sólo requiere un pequeño esfuerzo adicional.&lt;/p&gt;

&lt;p&gt;Esta práctica no es solamente aplicable en el contexto de TDD. También es muy interesante aplicarla cuando se está testeando un código a posteriori a partir de su especificación (&lt;a href=&quot;https://www.effective-software-testing.com/it-is-not-about-following-a-recipe&quot;&gt;specification-based testing&lt;/a&gt;), o cuando estamos caracterizando un código legacy (&lt;a href=&quot;https://michaelfeathers.silvrback.com/characterization-testing&quot;&gt;characterization testing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Como simple demostración de su aplicación, mostraremos un ejemplo escrito en Java.&lt;/p&gt;

&lt;p&gt;Fíjense en la siguiente aserción y el mensaje de error que obtenemos cuando falla:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.AssertionError:
Expected: is &amp;lt;Fraction@2d8e8c3a&amp;gt;
 	but: was &amp;lt;Fraction@2d8e84b8&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;¿Qué está fallando? ¿Creen que este mensaje de error nos ayudará en el futuro a diagnosticar qué está pasando?&lt;/p&gt;

&lt;p&gt;La respuesta es claramente que no.&lt;/p&gt;

&lt;p&gt;Pero con muy poco esfuerzo podemos añadir un poquito de código que puede aclarar muchísimo el mensaje de error. En este caso bastaría con implementar el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString()&lt;/code&gt; en la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fraction&lt;/code&gt; (que de hecho muchos IDEs pueden generar automáticamente).&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Fraction{&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;numerator=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numerator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;, denominator=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;denominator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;sc&quot;&gt;&apos;}&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora el mensaje de error que obtenemos para el fallo anterior sería:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.AssertionError:
Expected: is &amp;lt;Fraction{numerator=3, denominator=2}&amp;gt;
 	but: was &amp;lt;Fraction{numerator=1, denominator=2}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este mensaje de error es muchísimo más claro que el anterior y nos ayudará a ser más efectivos si, o cuando, este error vuelva a ocurrir en el futuro.&lt;/p&gt;

&lt;p&gt;Aclarar los mensajes de error nos ayuda incluso mientras hacemos TDD (o testing a posteriori) porque nos puede confirmar que el rojo que estábamos obteniendo es justo el que esperábamos, es decir, que tiene la causa que esperábamos y no otra. Si no hacemos esto corremos el riesgo de “programar por coincidencia”&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esta práctica te puede ser útil incluso si le pides a una IA que escriba los tests por ti, ya que te da otro criterio para evaluar los tests que la IA genera, 
y una manera sencilla de mejorarlos para que le sean más útiles a las personas que tengan que trabajar en el futuro con ellos.&lt;/p&gt;

&lt;p&gt;No desaprovechemos estas mejoras de productividad que podemos obtener con muy poco esfuerzo. Introduzcamos este pequeño hábito en nuestra práctica y ¡empecemos a mejorar nuestros rojos!&lt;/p&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Gracias a &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; por revisar la actualización en castellano de este post.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] &lt;strong&gt;Programming by Coincidence&lt;/strong&gt; es el título de uno de los &lt;em&gt;topics&lt;/em&gt; que se tratan en el libro &lt;a href=&quot;https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/&quot;&gt;The Pragmatic Programmer&lt;/a&gt; (topic 31 en la primera edición y &lt;em&gt;topic&lt;/em&gt; 38 en la edición del veinte aniversario). Textualmente, los autores dicen: “We should avoid programming by coincidence—relying on luck and accidental successes— in favor of programming deliberately”.&lt;/p&gt;

</description>
          <pubDate>2025-07-10T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/mejorar-nuestros-rojos</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/mejorar-nuestros-rojos</guid>
        </item>
      
    
      
        <item>
          <title>Experiencia en la Pamplona Software Crafters 2025</title>
          <description>&lt;p&gt;El pasado 26 y 27 de junio mi compañero &lt;a href=&quot;https://x.com/adelatorrefoss/&quot;&gt;Toño&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;yo&lt;/a&gt; estuvimos en la octava edición de la &lt;a href=&quot;https://pamplonaswcraft.com/&quot;&gt;Pamplona Software Crafters&lt;/a&gt;, un evento que reúne a personas interesadas en desarrollar software con éxito.&lt;/p&gt;

&lt;p&gt;Nuestra experiencia en el evento fue maravillosa: temas, conversaciones y gente interesantes, un espacio increíble, un ambiente acogedor y una comida excelente.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/2025-07-07-pamplonaSC-2025/PamploSC2025-1.png&quot; alt=&quot;Empieza la Pamplona Software Crafters&quot; style=&quot;display: block; margin: 20px auto 20px auto; width: 80%;&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;El evento tiene una parte de charlas preestablecidas pero también cuenta con un &lt;a href=&quot;https://estructurasliberadoras.com/menu-ls/open-space-technology/&quot;&gt;Open Space&lt;/a&gt;, de manera que parte del contenido del evento está abierto. Yo me animé a presentar dos propuestas en el Open Space y que, por suerte, salieron elegidas.&lt;/p&gt;

&lt;p&gt;La primera propuesta que presenté se tituló “Una ayuda para trabajar con Historias de Usuario”. En ella compartí una pequeña guía visual diseñada para ayudar a formular preguntas adecuadas según el momento en que se encuentre la historia de usuario. Esta guía relaciona el uso de &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt;, como criterio para evaluar buenas historias de usuario, y con las técnicas de splitting que nos ayudan a descomponer de forma efectiva.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/2025-07-07-pamplonaSC-2025/PamploSC2025-2.png&quot; alt=&quot;Propuesta: Una ayuda para trabajar con historias de usuario&quot; style=&quot;display: block; margin: 20px auto 20px auto; width: 80%;&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Escribimos sobre parte de lo que hablé en nuestro post &lt;a href=&quot;https://codesai.com/posts/2025/06/size-and-details-in-user-stories&quot;&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?&lt;/a&gt;. En breve publicaremos un segundo post que completa lo que expusimos en la conferencia y que creemos puede ser útil para aclarar el proceso de refinamiento de las historias de usuario.&lt;/p&gt;

&lt;p&gt;La segunda propuesta, titulada “Priorizar deuda técnica”, estuvo centrada en explorar diferentes técnicas que pueden facilitar nuestra toma de decisiones cuando tenemos que priorizar deuda técnica, y que forman parte de nuestro curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/2025-07-07-pamplonaSC-2025/PamploSC2025-3.png&quot; alt=&quot;Propuesta: Priorizar deuda técnica&quot; style=&quot;display: block; margin: 20px auto 20px auto; width: 80%;&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Una de las técnicas consiste en analizar la evolución del sistema a partir del historial de cambios del repositorio de control de versiones. Esto nos permite tener una visión más dinámica y contextual de qué partes de nuestra deuda técnica nos afectan más, y así nos ayudan a priorizarla. Además, este tipo de análisis, conocidos como &lt;a href=&quot;https://se-radio.net/2023/03/episode-554-adam-tornhill-on-behavioral-code-analysis/&quot;&gt;behavioral code analysis&lt;/a&gt;, nos ayudan a identificar patrones sobre cómo los desarrolladores interactúan con su base de código. Herramientas como &lt;a href=&quot;https://github.com/adamtornhill/code-maat&quot;&gt;Code Maat&lt;/a&gt; o &lt;a href=&quot;https://codescene.com/&quot;&gt;CodeScene&lt;/a&gt; nos permiten realizar este tipo de análisis, y pueden ser un grán complemento a la hora de priorizar la deuda técnica, e incluso de priorizar historias de usuario.&lt;/p&gt;

&lt;p&gt;Quiero aprovechar para agradecer a todos los asistentes la generosidad de sus aportaciones. También quiero darle las gracias, en especial, a mi compañero &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Toño&lt;/a&gt; por su apoyo durante toda la conferencia, que facilitó mucho que pudiera contribuir al contenido del evento.&lt;/p&gt;

&lt;p&gt;Para finalizar, quiero agradecer a los compañeros de &lt;a href=&quot;https://www.540deg.com/&quot;&gt;540&lt;/a&gt; su labor como organizadores de la &lt;a href=&quot;https://pamplonaswcraft.com/&quot;&gt;Pamplona Software Crafter&lt;/a&gt;. Hacen un trabajo excelente año tras año y, aunque quizás de manera algo diferente, estoy seguro de que seguirán haciéndolo en el futuro.&lt;/p&gt;
</description>
          <pubDate>2025-07-07T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/pamplonaSC-2025</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/pamplonaSC-2025</guid>
        </item>
      
    
      
        <item>
          <title>Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;In our previous post, &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, we talked about the distinction that the authors of &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;the GOOS book&lt;/a&gt; make between the &lt;strong&gt;peers&lt;/strong&gt; (real collaborators&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;) and the &lt;strong&gt;internals&lt;/strong&gt; of an object, and how this distinction was crucial for the maintainability of unit tests.&lt;/p&gt;

&lt;p&gt;We commented how in the tests we write, we should only rely on test doubles to simulate the peers of an object because they align with the behaviours  (roles, responsibilities&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;) that the behaviour under test directly depends on, not the classes it depends on. This practice is consistent with the recommendation: “mock roles, not objects”&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. This helps us focus on testing behaviour rather than implementation details.&lt;/p&gt;

&lt;p&gt;We also commented that test doubles should not simulate internal objects (any collaborator that is not a peer of the object under test), as they represent implementation details. Using test doubles for them can result in tests that are tightly coupled to structure rather than behaviour.&lt;/p&gt;

&lt;p&gt;So, in order to reduce the coupling of our tests to implementation details, it’s crucial that we correctly identify the peers of an object.&lt;/p&gt;

&lt;p&gt;Finally, we commented about the &lt;strong&gt;object peer stereotypes&lt;/strong&gt; which are heuristics presented by the GOOS authors to help us think about our design and identify peers.&lt;/p&gt;

&lt;p&gt;In this post, we’ll discuss different heuristics that we may apply to detect the peers of an object, or, in other words, to determine the boundaries of the unit under test. We’ll also examine the relationships between them.&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;heuristics-to-determine-the-boundaries-of-the-unit-under-test&quot;&gt;Heuristics to determine the boundaries of the unit under test.&lt;/h2&gt;

&lt;h3 id=&quot;heuristic-1-object-peer-stereotypes&quot;&gt;Heuristic 1: Object peer stereotypes.&lt;/h3&gt;

&lt;p&gt;According to the GOOS book an object’s peers are cohesive objects&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; that can be loosely categorized into three types of relationship:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;: “services that the object needs from its environment so that it can fulfill its responsibilities. The object cannot function without these services. It should not be possible to create the object without them.”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Notifications&lt;/strong&gt;: “objects that need to be kept up to date with the object’s activity. The object will notify interested peers whenever it changes state or performs a significant action. Notifications are “fire and forget” (the object neither knows nor cares which peers are listening).”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Adjustments&lt;/strong&gt;: “objects that tweak or adapt the object’s behaviour to the needs of the system. This includes policy objects that make decisions on the object’s behalf (think &lt;a href=&quot;https://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;Strategy Pattern&lt;/a&gt;), and component parts of the object if it’s a composite.”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These peer stereotypes should be considered as heuristics to help us think about our design, not as hard rules.&lt;/p&gt;

&lt;p&gt;They help us define the unit’s boundaries because &lt;strong&gt;dependencies, notifications and adjustments should be outside the unit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, we will introduce two more general heuristics that produce coarser-grained units and explain how these heuristics relate to one of the object peer stereotypes: &lt;strong&gt;dependencies&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;heuristic-2-firs-ness&quot;&gt;Heuristic 2: FIRS-ness.&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;FIRS properties&lt;/strong&gt; (&lt;strong&gt;Fast&lt;/strong&gt;, &lt;strong&gt;Isolated&lt;/strong&gt;, &lt;strong&gt;Repeatable&lt;/strong&gt;, &lt;strong&gt;Self-validating&lt;/strong&gt;),&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt; provide an interesting guideline for delineating the boundaries of a unit.&lt;/p&gt;

&lt;p&gt;According to this idea, any code that adheres to the &lt;strong&gt;FIRS properties&lt;/strong&gt; (i.e., exhibits &lt;strong&gt;FIRS-ness&lt;/strong&gt;) belongs within the unit, while any code that violates any of these properties is an awkward collaboration (a dependency that impairs testability), and should be pushed outside the unit.&lt;/p&gt;

&lt;p&gt;We can push &lt;strong&gt;FIRS-violating&lt;/strong&gt; code (i.e., awkward collaborations) outside the unit by applying the &lt;a href=&quot;https://martinfowler.com/articles/dipInTheWild.html&quot;&gt;Dependency Inversion Principle (DIP)&lt;/a&gt;. This allows us to control how the unit depends on the awkward dependencies, and enables the use of test doubles in our test to simulate the behaviour of the awkward dependencies, thereby avoiding the testability problems&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt; (i.e., &lt;strong&gt;FIRS violations&lt;/strong&gt;) they introduce.&lt;/p&gt;

&lt;h3 id=&quot;heuristic-3-detecting-effects&quot;&gt;Heuristic 3: Detecting effects.&lt;/h3&gt;

&lt;p&gt;Another guideline to determine unit boundaries is inspired by the separation of &lt;strong&gt;effectful&lt;/strong&gt;&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt; and &lt;strong&gt;non-effectful&lt;/strong&gt; (pure) code in functional programming. From this perspective, unit boundaries emerge “wherever an effect needs to be performed”.&lt;/p&gt;

&lt;p&gt;If state mutation isn’t considered an effect, the unit boundaries defined using the &lt;strong&gt;FIRS-ness concept&lt;/strong&gt; and the &lt;strong&gt;isolating-non-effectful code guideline&lt;/strong&gt; would mostly align. This isn’t surprising, as &lt;strong&gt;FIRS violations&lt;/strong&gt; are usually caused by &lt;strong&gt;effects&lt;/strong&gt; (except in the case of really slow computations).&lt;/p&gt;

&lt;h2 id=&quot;how-are-these-heuristics-related&quot;&gt;How are these heuristics related?&lt;/h2&gt;

&lt;p&gt;So far, we’ve looked at three heuristics that lead us to unit testable designs.&lt;/p&gt;

&lt;p&gt;We already commented that the unit boundaries defined using the &lt;strong&gt;FIRS-ness concept&lt;/strong&gt; and the &lt;strong&gt;isolating-non-effectful code guideline&lt;/strong&gt; would mostly align because &lt;strong&gt;FIRS violations&lt;/strong&gt; are usually caused by &lt;strong&gt;effects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, we believe that the unit boundaries, derived from applying the &lt;strong&gt;FIRS-ness concept&lt;/strong&gt;  or detecting &lt;strong&gt;effects&lt;/strong&gt;, closely align with those identified when using the &lt;strong&gt;“dependencies” peer stereotype&lt;/strong&gt;. Remember that this stereotype is defined as “”services an object needs from its environment to fulfill its responsibilities”.&lt;/p&gt;

&lt;p&gt;Additionally, these unit boundaries align with those in the classic style of TDD, where test doubles are primarily used as isolation tools to avoid &lt;strong&gt;effects&lt;/strong&gt; or &lt;strong&gt;FIRS violations&lt;/strong&gt; in tests.&lt;/p&gt;

&lt;p&gt;Notice that we have focused on the &lt;strong&gt;“dependencies” peer stereotype&lt;/strong&gt; as the heuristic that defines unit boundaries similar to those derived from applying the &lt;strong&gt;FIRS-ness&lt;/strong&gt; and &lt;strong&gt;detecting effects&lt;/strong&gt; heuristics. Later in this post, we will explore how the two other object peer stereotypes, &lt;strong&gt;adjustments&lt;/strong&gt; and &lt;strong&gt;notifications&lt;/strong&gt;, contribute to achieving finer-grained units and more maintainable tests.&lt;/p&gt;

&lt;h2 id=&quot;how-are-these-heuristics-related-to-the-ports--adapters-pattern&quot;&gt;How are these heuristics related to the &lt;a href=&quot;https://jmgarridopaz.github.io/content/hexagonalarchitecture.html&quot;&gt;Ports &amp;amp; Adapters pattern&lt;/a&gt;?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FIRS-ness&lt;/strong&gt; and &lt;strong&gt;detecting effects&lt;/strong&gt; heuristics will delineate boundaries where our application is testable independently of its context, making them a useful starting point for defining the ports of our application. Where they fall short, though, is in expressing the ports’ interfaces in terms of the application, using only these two heuristics, we could end up with port interfaces that are not aligned with the application’s domain language&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In contrast, using the &lt;strong&gt;dependencies peer stereotype&lt;/strong&gt; provides an advantage over the previous two heuristics by leading to better-designed port interfaces. Recall that this stereotype is defined as “services an object needs from its environment to fulfill its responsibilities”.  As a result, the port interfaces created using this approach align more closely with the &lt;strong&gt;ports &amp;amp; adapters pattern&lt;/strong&gt; because they will reflect the language and concepts defined by the application itself.&lt;/p&gt;

&lt;p&gt;Moreover, we can also apply the other two other object peer stereotypes, &lt;strong&gt;adjustments&lt;/strong&gt; and &lt;strong&gt;notifications&lt;/strong&gt;, to design finer-grained, context-independent units. This approach may
result in unit boundaries that align with those produced by a generalization of the &lt;strong&gt;ports &amp;amp; adapters pattern&lt;/strong&gt; (remember that this pattern only applies at the application boundaries). &lt;a href=&quot;https://alistaircockburn.com/&quot;&gt;Alistair Cockburn&lt;/a&gt; recently referred to this generalization as the &lt;a href=&quot;https://alistaircockburn.com/Component%20plus%20strategy.pdf&quot;&gt;Component + Strategy pattern&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-heuristics-do-we-usually-apply-to-determine-the-boundaries-of-the-unit-under-test&quot;&gt;What heuristics do we usually apply to determine the boundaries of the unit under test?&lt;/h2&gt;

&lt;p&gt;All of them.&lt;/p&gt;

&lt;p&gt;In the context of retrofitting tests into legacy code, we focus primarily on detecting *effects** and &lt;strong&gt;FIRS-ness&lt;/strong&gt; violations to determine where to introduce seams, while keeping in mind that the interfaces coupled to the resulting tests are likely too low-level and not well-suited for the application, suffering from the &lt;a href=&quot;https://wiki.c2.com/?MimicAdapter&quot;&gt;Mimic Adapter antipattern&lt;/a&gt;&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once the tests are in place, we will refactor toward more cohesive and higher-level interfaces, using the &lt;strong&gt;object peer stereotypes&lt;/strong&gt; and the &lt;a href=&quot;https://alistaircockburn.com/Component%20plus%20strategy.pdf&quot;&gt;Component + Strategy pattern&lt;/a&gt; as guiding principles to improve modularity and design clarity.&lt;/p&gt;

&lt;p&gt;When doing TDD, identifying the suitable unit boundaries and interfaces can be more challenging because we must infer them from the requirements. In this case, we use all three heuristics to determine the boundaries and interfaces, and produce a testable design.&lt;/p&gt;

&lt;p&gt;We identify awkward collaborations by detecting &lt;strong&gt;effects&lt;/strong&gt; or &lt;strong&gt;FIRS-ness&lt;/strong&gt; violations in the specification. Additionally, we use &lt;strong&gt;object peer stereotypes&lt;/strong&gt;, especially the &lt;strong&gt;dependencies peer stereotype&lt;/strong&gt;, to define interfaces in terms of the unit we are test-driving.&lt;/p&gt;

&lt;h2 id=&quot;what-about-the-two-other-peer-stereotypes-notifications-and-adjustments-or-policies&quot;&gt;What about the two other peer stereotypes: “notifications” and “adjustments or policies”?&lt;/h2&gt;

&lt;p&gt;So far we have only talked about using the &lt;strong&gt;dependencies peer stereotype&lt;/strong&gt; to delimit the boundaries of the unit under test.&lt;/p&gt;

&lt;p&gt;There are two other object peer stereotypes, &lt;strong&gt;notifications&lt;/strong&gt; and &lt;strong&gt;adjustments&lt;/strong&gt;, what about them?&lt;/p&gt;

&lt;p&gt;In the following sections, we’ll see how these two other object peer stereotypes can further separate concerns and keep cohesion, leading to finer-grained units and more maintainable code and tests.&lt;/p&gt;

&lt;h3 id=&quot;adjustments-peer-stereotype&quot;&gt;“Adjustments” peer stereotype.&lt;/h3&gt;

&lt;p&gt;When variants for some part of an object’s behaviour exist from the outset, or when a part of an object’s behavior begins to evolve at a different pace than the rest, there are various ways to adjust the code to accommodate these behavioral variations.&lt;/p&gt;

&lt;p&gt;Some available options are the parametric option, the polymorphic option and the compositional option.&lt;/p&gt;

&lt;p&gt;Not all options have the same benefits and liabilities. We think that the compositional option one is usually the best suited in object-oriented code.&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we choose to add these variations through composition, we need to encapsulate it first in a separate abstraction to maintain the object’s cohesion. This new abstraction would be an &lt;strong&gt;adjustment&lt;/strong&gt;. In this way adjustments can be used to tweak or adapt the object’s behaviour to the needs of the system by using composition.&lt;/p&gt;

&lt;p&gt;To achieve this separation, we apply the &lt;a href=&quot;https://martinfowler.com/articles/dipInTheWild.html#SynopsisOfTheDip&quot;&gt;dependency inversion principle&lt;/a&gt;, to ensure the object depends on the new abstraction rather than a specific implementation of it. We then use &lt;a href=&quot;https://martinfowler.com/articles/dipInTheWild.html#YouMeanDependencyInversionRight&quot;&gt;dependency injection&lt;/a&gt; to decide which concrete implementation of the adjustment we want to use.&lt;/p&gt;

&lt;p&gt;The resulting object’s code will be protected from changes in the concrete adjustments&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, separating adjustments from the object not only results in better design but also enables us to write more maintainable tests.&lt;/p&gt;

&lt;p&gt;On one hand, we can write tests focused solely on the object’s core behavior by using test doubles to simulate any adjustments. This approach ensures the object is tested independently of concrete implementations of its adjustments.&lt;/p&gt;

&lt;p&gt;Then, we can write separate tests that check the behaviour of each concrete variant of the adjustment.&lt;/p&gt;

&lt;p&gt;This testing approach makes the object’s tests more focused and maintainable. By decoupling them from specific adjustments, we ensure they remain unaffected by changes in or additions of new adjustment implementations.&lt;/p&gt;

&lt;h3 id=&quot;notifications-peer-stereotype&quot;&gt;“Notifications” peer stereotype.&lt;/h3&gt;

&lt;p&gt;Sometimes there are secondary behaviours associated with an object’s state changes or significant actions. Adding these secondary behaviors directly to the object violates the  &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;single responsibility principle&lt;/a&gt; (SRP) and introduces &lt;strong&gt;temporal coupling&lt;/strong&gt;&lt;a href=&quot;#nota13&quot;&gt;&lt;sup&gt;[13]&lt;/sup&gt;&lt;/a&gt; between the object’s core behavior and its associated secondary behaviours.&lt;/p&gt;

&lt;p&gt;To maintain SRP, the associated secondary behaviors can be encapsulated in separate collaborators. 
&lt;script src=&quot;https://gist.github.com/trikitrok/58d85160a78b8fb8b365155c448bccec.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;However, now the object becomes tightly coupled to all those collaborators. We haven’t removed the temporal coupling.&lt;/p&gt;

&lt;p&gt;This tightly coupled design introduces significant difficulties in development, maintenance, and testing. Each time a new secondary behavior is added, the object and its tests must be modified, increasing the risk of bugs and making the codebase more expensive to maintain.&lt;/p&gt;

&lt;p&gt;Furthermore, this kind of design often results in brittle tests, which break frequently as the system evolves. This brittleness is commonly blamed on test doubles, instead of recognizing the underlying design flaws&lt;a href=&quot;#nota14&quot;&gt;&lt;sup&gt;[14]&lt;/sup&gt;&lt;/a&gt;. We should instead “listen to our tests”&lt;a href=&quot;#nota15&quot;&gt;&lt;sup&gt;[15]&lt;/sup&gt;&lt;/a&gt; and improve the design flaws using &lt;strong&gt;notifications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Notifications act as a decoupling mechanism, preventing temporal coupling between the object’s behavior and the secondary behaviors encapsulated in its collaborators.&lt;/p&gt;

&lt;p&gt;Through notifications the object merely signals interested peers (if any) whenever it changes state or performs a significant action.&lt;/p&gt;

&lt;p&gt;These notifications are “fire and forget” commands&lt;a href=&quot;#nota16&quot;&gt;&lt;sup&gt;[16]&lt;/sup&gt;&lt;/a&gt;, i.e., the object neither knows nor cares which peers might be listening. This ensures loose coupling between components, making the design much more flexible and adaptable to change.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/07580367f29198fcea8b967508da1143.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Once notifications are in place, we should avoid checking the object’s behaviour along with all its associated secondary behaviours.&lt;/p&gt;

&lt;p&gt;The reason is that including associated secondary behaviors in the object’s tests would require creating test doubles for both the peers of the object and the peers of the notified collaborators, resulting in complex test setups that are difficult to maintain. This difficulty increases as the number of secondary behaviors grows.&lt;/p&gt;

&lt;p&gt;Instead, we can both simplify our tests and avoid the brittleness described earlier by taking advantage of notifications.&lt;/p&gt;

&lt;p&gt;First, we write tests solely focused on verifying that the object’s behaviour correctly triggers the appropriate notifications. We use test doubles&lt;a href=&quot;#nota17&quot;&gt;&lt;sup&gt;[17]&lt;/sup&gt;&lt;/a&gt; to simulate the notifications in these tests.&lt;/p&gt;

&lt;p&gt;Next, we write separate tests to confirm that a notification triggers the desired secondary behaviors in its listeners. These tests are decoupled from the object that produces the notifications.&lt;/p&gt;

&lt;p&gt;This approach makes the object’s tests more focused and maintainable because it decouples them from changes or additions to associated secondary behaviors.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;This post explores three different heuristics for defining unit boundaries that can be applied both when retrofitting tests in legacy code and when doing TDD: GOOS book’s &lt;strong&gt;object peer stereotypes&lt;/strong&gt;, &lt;strong&gt;FIRS-ness&lt;/strong&gt; and &lt;strong&gt;detecting effects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We explore how these three different approaches often lead to similar unit boundaries, how they can complement one another. Boundaries identified through &lt;strong&gt;FIRS-ness&lt;/strong&gt; or &lt;strong&gt;detecting effects&lt;/strong&gt; often are very similar to the ones derived from the &lt;strong&gt;“dependencies” peer stereotype&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We also highlight that the advantage of the &lt;strong&gt;“dependencies” peer stereotype&lt;/strong&gt; is its focus on what “the object needs”. This focus leads to interfaces expressed in the language of their client.&lt;/p&gt;

&lt;p&gt;Additionally, we explain how these heuristics can aid in defining application boundaries, drawing a connection with the &lt;strong&gt;Ports &amp;amp; Adapters pattern&lt;/strong&gt;. Again the &lt;strong&gt;“dependencies” peer stereotype&lt;/strong&gt;’s emphasis on the object’s explicit needs results in better interfaces, helping prevent the  &lt;a href=&quot;https://wiki.c2.com/?MimicAdapter&quot;&gt;mimic adapter&lt;/a&gt; antipattern.&lt;/p&gt;

&lt;p&gt;Finally, we see how the &lt;strong&gt;adjustments&lt;/strong&gt; and &lt;strong&gt;notifications&lt;/strong&gt; peer stereotypes, both reduce coupling, improve cohesion, and result in more maintainable and focused test suites.&lt;/p&gt;

&lt;p&gt;In future posts, we’ll discuss other techniques for detecting peers that are based on detecting test smells, leveraging domain knowledge, or design patterns.&lt;/p&gt;

&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;

&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/franiglesias/&quot;&gt;Fran Iglesias&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/mjtordesillas/&quot;&gt;Manu Tordesillas&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@petra-nesti-1766376/&quot;&gt;Petra Nesti&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.baerbak.com/&quot;&gt;Flexible, Reliable Software Using Patterns and Agile Development&lt;/a&gt;, &lt;a href=&quot;https://pure.au.dk/portal/en/persons/hbc%40cs.au.dk&quot;&gt;Henrik Bærbak Christensen&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;,  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/213172609-hexagonal-architecture-explained&quot;&gt;Hexagonal Architecture Explained&lt;/a&gt;, &lt;a href=&quot;https://alistaircockburn.com/&quot;&gt;Alistair Cockburn&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://alistaircockburn.com/Component%20plus%20strategy.pdf&quot;&gt;Component-plus-Strategy generalizes Ports-and-Adapters&lt;/a&gt;, &lt;a href=&quot;https://alistaircockburn.com/&quot;&gt;Alistair Cockburn&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/dipInTheWild.html&quot;&gt;DIP in the Wild&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/brettschuchert/&quot;&gt;Brett L. Schuchert&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;What Is Functional Programming?&lt;/a&gt;, &lt;a href=&quot;https://blog.jenkster.com/&quot;&gt;Kris Jenkins&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=p1fXJyomXNQ&quot;&gt;Native and browser SPA versions using re-frame, ClojureScript and ReactNative&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/francesc-guillen-45944b/&quot;&gt;Francesc Guillen&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Any object that helps a given object to fulfil its responsibilities is called a collaborator. It seems that this etymology comes from &lt;a href=&quot;https://en.wikipedia.org/wiki/Class-responsibility-collaboration_card&quot;&gt;Class-responsibility-collaboration cards&lt;/a&gt; originally proposed by &lt;a href=&quot;https://en.wikipedia.org/wiki/Ward_Cunningham&quot;&gt;Ward Cunningham&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; as a teaching tool in their paper &lt;a href=&quot;https://c2.com/doc/oopsla89/paper.html&quot;&gt;A Laboratory For Teaching Object-Oriented Thinking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In that paper, they write “the last dimension we use in characterizing object designs is the collaborators of an object. We name as collaborators objects which will send or be sent messages in the course of satisfying responsibilities.”&lt;/p&gt;

&lt;p&gt;In our previous article, &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, we explained that according to the GOOS book the collaborators of an object belong to one of two categories: peers (real collaborators) and internals (implementation details).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] The OO style described in the GOOS book is influenced by &lt;a href=&quot;https://wirfs-brock.com/rebecca/&quot;&gt;Rebecca Wirfs-Brock&lt;/a&gt;’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Responsibility-driven_design&quot;&gt;Responsibility-driven design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] From &lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt; by  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] This post originated from a response to a comment on the post &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Following the &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;single responsibility principle&lt;/a&gt;, i.e., objects that are cohesive. See section &lt;em&gt;Object Peer Stereotypes&lt;/em&gt; in chapter 6, &lt;em&gt;Object-Oriented Style&lt;/em&gt;, of the GOOS book.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] In our post &lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;, we explain what each of the &lt;strong&gt;FIRS properties&lt;/strong&gt; means for us.&lt;/p&gt;

&lt;p&gt;We also comment about the origin and history of the &lt;strong&gt;FIRST acronym&lt;/strong&gt;, citing original sources.&lt;/p&gt;

&lt;p&gt;Finally, we explain how we interpret &lt;strong&gt;isolated&lt;/strong&gt; differently than the authors of the the &lt;strong&gt;FIRST acronym&lt;/strong&gt;, our definition is more aligned with Beck’s interpretation of &lt;strong&gt;isolated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] &lt;strong&gt;Isolated&lt;/strong&gt; violations can also be avoided by using fixtures, but this may lead to slower tests that violate &lt;strong&gt;Fast&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With the advent of technologies such as &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt;, tests that were traditionally classified as integration tests can now adhere to the &lt;strong&gt;FIRS properties&lt;/strong&gt;.  Using &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt; helps maintain isolation, ensuring the tests run independently and are repeatable regardless of the developer’s local setup.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Effectful code performs effects, but what are effects? Let’s try to informally explain it.&lt;/p&gt;

&lt;p&gt;Any code that uses any input that isn’t in its argument list (or is injected through its constructor in the case of objects), or does anything that isn’t part of its return value is considered effectful, and those hidden inputs and outputs are effects.&lt;/p&gt;

&lt;p&gt;Most people call the hidden inputs and outputs side-effects, but some people use the term &lt;strong&gt;side-effect&lt;/strong&gt; only for the hidden outputs, and the term &lt;strong&gt;side-causes&lt;/strong&gt; for the hidden inputs (like &lt;a href=&quot;https://blog.jenkster.com/&quot;&gt;Kris Jenkins&lt;/a&gt; in his post &lt;a href=&quot;https://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;What Is Functional Programming?&lt;/a&gt;) to highlight their different nature.&lt;/p&gt;

&lt;p&gt;According to that distinction, a side-effect is something a program does to its environment, and a side-cause is something a program requires from its environment.&lt;/p&gt;

&lt;p&gt;Effectful code is much harder to test and understand than pure code.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] According to &lt;a href=&quot;https://alistaircockburn.com/&quot;&gt;Alistair Cockburn&lt;/a&gt;, port interfaces should be expressed in the language of the application:&lt;/p&gt;

&lt;p&gt;“Every interaction between the app and the outside world happens at a port interface, using the interface language the app itself defines” (in page 12 of the preview edition of  his book &lt;a href=&quot;https://www.goodreads.com/book/show/213172609-hexagonal-architecture-explained&quot;&gt;Hexagonal Architecture Explained&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We observe that the interfaces that arise from looking for &lt;strong&gt;FIRS violations&lt;/strong&gt; or &lt;strong&gt;detecting effects&lt;/strong&gt; tend to have more risk of presenting a too low level of abstraction, falling in the  &lt;a href=&quot;https://wiki.c2.com/?MimicAdapter&quot;&gt;mimic adapter&lt;/a&gt; antipattern. The &lt;strong&gt;object peer stereotypes&lt;/strong&gt; help in alleviating that risk.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] Since dependency-breaking techniques carry some risk as they are applied without tests, we try to reduce this risk by introducing very thin layers that isolate the minimum possible amount of code to get isolation. Therefore, they will most likely be at a lower level of abstraction than what our application requires and will not align with the terms of our application. They are &lt;a href=&quot;https://wiki.c2.com/?MimicAdapter&quot;&gt;mimic adapters&lt;/a&gt; which, in this context, is not an antipattern, it’s exactly what we need to reduce risks and introduce tests.&lt;/p&gt;

&lt;p&gt;However, if, once we have tests in place, we don’t refactor these low level interfaces, we may face excessive coupling problems in our tests (see our post &lt;a href=&quot;https://codesai.com/posts/2024/10/ill-designed-ports&quot;&gt;An example of wrong port design detection and refinement&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] In the chapter &lt;em&gt;Deriving Strategy Pattern&lt;/em&gt; of his book &lt;a href=&quot;https://www.baerbak.com/&quot;&gt;Flexible, Reliable Software Using Patterns and Agile Development&lt;/a&gt;, &lt;a href=&quot;https://pure.au.dk/portal/en/persons/hbc%40cs.au.dk&quot;&gt;Henrik Bærbak Christensen&lt;/a&gt; describes and analyses in depth four options, which he calls proposals, to accommodate an object-oriented design to this kind of behavioral variations: &lt;em&gt;source tree copy proposal&lt;/em&gt;, &lt;em&gt;parametric proposal&lt;/em&gt;, &lt;em&gt;polymorphic proposal&lt;/em&gt; and &lt;em&gt;compositional proposal&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;compositional proposal&lt;/em&gt; has many interesting benefits and a few liabilities. Read the whole analysis there.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12] This has the interesting property of changing behavior by adding new production code instead of modifying existing one. This property is characterized as &lt;strong&gt;Change by Addition&lt;/strong&gt; (in &lt;a href=&quot;https://pure.au.dk/portal/en/persons/hbc%40cs.au.dk&quot;&gt;Henrik Bærbak Christensen&lt;/a&gt; book), &lt;a href=&quot;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&quot;&gt;Open-Closed Principle&lt;/a&gt;, or &lt;a href=&quot;https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I prefer the last description.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota13&quot;&gt;&lt;/a&gt; [13]  “When two actions are bundled together into one module just because they happen to occur at the same time.” See the &lt;a href=&quot;https://en.wikipedia.org/wiki/Coupling_(computer_programming)&quot;&gt;entry about Coupling in Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota14&quot;&gt;&lt;/a&gt; [14] Another example of blaming a tool or technique rather than our design or how we use the tool or technique.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota15&quot;&gt;&lt;/a&gt; [15] By interpreting difficulties in testing as feedback signaling that our design might need improvement.&lt;/p&gt;

&lt;p&gt;Have a look at this interesting &lt;a href=&quot;https://web.archive.org/web/20210426022938/http://www.mockobjects.com/search/label/listening%20to%20the%20tests&quot;&gt;series of posts about listening to the tests&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;. It’s a raw version of the content that you’ll find in chapter 20, &lt;em&gt;Listening to the tests&lt;/em&gt;, of their book.&lt;/p&gt;

&lt;p&gt;In fact, according to  &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt; mocks were designed as a feedback tool for designing OO code following the &lt;a href=&quot;https://martinfowler.com/bliki/TellDontAsk.html&quot;&gt;‘Tell, Don’t Ask’ principle&lt;/a&gt;. You can read more about this in this &lt;a href=&quot;https://groups.google.com/g/growing-object-oriented-software/c/dOmOIafFDcI/m/cmSUeZ_I8MMJ&quot;&gt;conversation in the Growing Object-Oriented Software Google Group&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The feedback usually comes in the form of “pain” 😅.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota16&quot;&gt;&lt;/a&gt; [16] See &lt;a href=&quot;https://www.martinfowler.com/bliki/CommandQuerySeparation.html&quot;&gt;Command Query Separation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota17&quot;&gt;&lt;/a&gt; [17] Since notifications are commands, we may use either mocks, fakes or spies.&lt;/p&gt;

</description>
          <pubDate>2025-07-03T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries</guid>
        </item>
      
    
      
        <item>
          <title>¿Tamaño y nivel de detalle adecuados para una historia de usuario?</title>
          <description>&lt;h2 id=&quot;introdución&quot;&gt;Introdución.&lt;/h2&gt;

&lt;p&gt;Uno de los aspectos que genera más confusión a la hora de entender las historias de usuarios es su tamaño. Esto se debe a que no hay un único tamaño adecuado para una historia de usuario, sino que este depende de la distancia en el tiempo al momento de desarrollar la historia.&lt;/p&gt;

&lt;p&gt;El tamaño de una historia de usuario es proporcional a la cantidad de funcionalidad que abarca (alcance), y por tanto también es proporcional a la cantidad de riesgo e incertidumbre que contiene.&lt;/p&gt;

&lt;p&gt;Otro aspecto confuso es el nivel de detalle de la historia de usuario. Este está relacionado con lo precisa que necesita ser la historia de usuario, ya que los detalles acotan y aclaran los límites de la historia. Aquí ocurre un fenómeno similar al que comentamos para el tamaño, es decir, no existe un único nivel de detalle adecuado para una historia de usuario, sino que este cambiará según nos acercamos al momento de desarrollar una historia.&lt;/p&gt;

&lt;p&gt;En este post vamos a intentar arrojar un poco de luz sobre estos dos aspectos de las historias de usuario,&lt;/p&gt;

&lt;h2 id=&quot;cómo-deberían-variar-el-tamaño-y-el-nivel-de-detalle-adecuados-de-una-historia-de-usuario&quot;&gt;¿Cómo deberían variar el tamaño y el nivel de detalle adecuados de una historia de usuario?&lt;/h2&gt;

&lt;p&gt;Según nos acercamos al momento de desarrollar la historia, nos interesa que ocurran los siguientes fenómenos:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Que su tamaño disminuya.&lt;/li&gt;
  &lt;li&gt;Que su nivel de detalle aumente.&lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/posts/user-stories-size.excalidraw.png&quot; alt=&quot;Variación de tamaño y nivel de detalle adecuados con el tiempo donde el tamaño de los cuadros de colores ilustra el tamaño de cada historia&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Tamaño y nivel de detalle adecuados frente al tiempo, donde el tamaño de los cuadros ilustra el tamaño de las historias&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;relaciones-entre-la-evolución-del-tamaño-y-el-nivel-de-detalle&quot;&gt;Relaciones entre la evolución del tamaño y el nivel de detalle.&lt;/h2&gt;

&lt;p&gt;Existe una curiosa relación entre el tamaño y el nivel de detalle.&lt;/p&gt;

&lt;p&gt;Si miramos con atención como acotamos el alcance de una historia de usuario&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;, podemos observar que detallar la historia siempre es un paso previo para reducir el tamaño de la historia.&lt;/p&gt;

&lt;p&gt;Vamos a poner un ejemplo, dada esta historia de usuario:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Quiero ordenar productos.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si detallamos lo que significa ordenar, nos quedaría:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt; Quiero ordenar productos&lt;/div&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;	* Por fecha de compra.&lt;/div&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;	* Por coste del producto.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;que, obviamente, tiene el mismo tamaño pero más nivel de detalle.&lt;/p&gt;

&lt;p&gt;Si decidimos partir esta historia en dos, nos podrían salir las siguientes historias:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Quiero ordenar productos por su fecha de compra.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;y&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Quiero ordenar productos por su coste.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora cada una tiene menor tamaño pero conservando el nivel de detalle de la inicial.
Por tanto, vemos que existe una relación entre detallar una historia de usuario y reducir su tamaño, ya sea partiéndola o no&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;por-qué-dependiendo-del-momento-el-tamaño-y-el-nivel-de-detalle-adecuados-varían&quot;&gt;¿Por qué dependiendo del momento el tamaño y el nivel de detalle adecuados varían?&lt;/h2&gt;

&lt;p&gt;Hay al menos dos momentos del tiempo dónde debería cambiar el tamaño de las historias para que sea eficiente trabajar con ellas.&lt;/p&gt;

&lt;p&gt;El primer momento, T&lt;sub&gt;r&lt;/sub&gt;, ocurre poco antes de presentar una historia al equipo en, la que suele denominarse, sesión de refinamiento. El segundo momento es poco antes de T&lt;sub&gt;d&lt;/sub&gt;. T&lt;sub&gt;d&lt;/sub&gt;, como indica la gráfica, es el momento en que desarrollamos la historia.&lt;/p&gt;

&lt;p&gt;Idealmente no debería pasar demasiado tiempo entre T&lt;sub&gt;r&lt;/sub&gt; y T&lt;sub&gt;d&lt;/sub&gt;.&lt;/p&gt;

&lt;p&gt;Analicemos cada uno de ellos.&lt;/p&gt;

&lt;h3 id=&quot;nivel-de-detalle-adecuado-dependiendo-del-momento&quot;&gt;Nivel de detalle adecuado dependiendo del momento.&lt;/h3&gt;

&lt;h4 id=&quot;desde-su-creación-t0-hasta-antes-del-momento-tr&quot;&gt;Desde su creación, (T&lt;sub&gt;0&lt;/sub&gt;), hasta antes del momento (T&lt;sub&gt;r&lt;/sub&gt;).&lt;/h4&gt;

&lt;p&gt;Detallamos poco principalmente porque queremos evitar tanto malgastar tiempo (&lt;a href=&quot;https://en.wikipedia.org/wiki/Muda_(Japanese_term)&quot;&gt;waste&lt;/a&gt;) como descartar posibles opciones interesantes.&lt;/p&gt;

&lt;p&gt;Hay varias formas en las que podemos incurrir en waste. En este caso concreto, se podrían presentar dos formas de waste:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Trabajo innecesario&lt;/strong&gt;.
Cuanto más alejados estamos de T&lt;sub&gt;r&lt;/sub&gt; mayor es la incertidumbre sobre qué historias de usuario acabarán desarrollándose o no, por tanto, si invertimos mucho tiempo en detallarla en este momento, la probabilidad de desperdiciar tiempo y energía en un trabajo innecesario es alta&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. La inversión en detallar se materializaría como trabajo innecesario si al final no se acaba desarrollando la historia&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Recuperación de contexto&lt;/strong&gt; como forma de retrabajo.
Si ha pasado mucho tiempo desde la última vez que se trabajó en la historia, necesitamos volver a hacer un esfuerzo para recordar qué aspectos se discutieron tiempo atrás&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En cuanto a mantener las opciones abiertas, nos referimos a no tomar decisiones que puedan descartar opciones antes de tener suficiente información, ya que si las tomamos prematuramente existe una mayor probabilidad de que estas sean erróneas &lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. Por tanto, para mantener nuestras opciones abiertas lo mejor es no decidir hasta el &lt;a href=&quot;https://jimmiebutler.com/the-last-responsible-moment/&quot;&gt;último momento responsable&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;en-tr&quot;&gt;En T&lt;sub&gt;r&lt;/sub&gt;.&lt;/h4&gt;

&lt;p&gt;En este caso el detalle que vamos a añadir tiene como finalidad hacer la historia más pequeña. Hablaremos sobre esto en la sección de relacionada con el tamaño adecuado de una historia de usuario.&lt;/p&gt;

&lt;h4 id=&quot;poco-antes-de-td&quot;&gt;Poco antes de T&lt;sub&gt;d&lt;/sub&gt;.&lt;/h4&gt;

&lt;p&gt;Finalmente, en este momento necesitamos detallar mucho más porque queremos eliminar cualquier posible ambigüedad en las historias de usuarios para desarrollarlas sin malentendidos y suposiciones erróneas.&lt;/p&gt;

&lt;p&gt;Los criterios de aceptación&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt; y los ejemplos sirven para detallar mejor una historia de usuario y aumentar su claridad.&lt;/p&gt;

&lt;p&gt;La razón por la que queremos ganar claridad es para asegurar uno de los aspectos más importantes de las historias de usuario, la confirmación&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;. Es decir, queremos ser capaces de determinar cuándo una historia de usuario está acabada y funcionando como se esperaba.&lt;/p&gt;

&lt;p&gt;El uso de ejemplos en las historias de usuario juega un papel muy importante porque clarifican los criterios de aceptación que normalmente están en un nivel de abstracción mayor.&lt;/p&gt;

&lt;p&gt;Por ejemplo, dada una historia relacionada con el registro de usuarios en una site internacional de venta de bebidas con bajo contenido alcohólico podríamos tener el siguiente criterio de aceptación:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt; Debe ser mayor de edad.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si agregamos unos cuantos ejemplos podríamos aclarar la complejidad que ese criterio de aceptación podría estar ocultado para algunos de los participantes en la sesión de refinamiento.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Dado que resido en Japón y tengo 18, cuando intento registrarme, me indica que soy menor de edad y no me deja finalizar el registro.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Dado que resido en Alemania, tengo 18 y he rellenado correctamente los otros datos del formulario, cuando finalizó el registro, veo un mensaje de agradecimiento por el registro.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Al escribir ejemplos podrían emerger varios escenarios. Por tanto, los ejemplos no sólo clarifican, sino también pueden ayudar a preguntarnos sobre otros escenarios posibles&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Siguiendo con el caso expuesto, podríamos preguntarnos:
¿Qué escenario no me permite registrarme si resido en Alemania? ¿Cuántos países tenemos que tener en cuenta?.&lt;/p&gt;

&lt;p&gt;Es importante además que todas las partes involucradas en las historias de usuario (Producto, Devs, QAs, etc) estén de acuerdo sobre los criterios de aceptación. Esta claridad compartida ayuda a que todos los participantes comprendan mejor la situación y reduce la posibilidad de que se produzcan diferentes interpretaciones sobre lo que cada uno espera de la historia de usuario.&lt;/p&gt;

&lt;h3 id=&quot;tamaño-adecuado-dependiendo-del-momento10&quot;&gt;Tamaño adecuado dependiendo del momento&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;.&lt;/h3&gt;

&lt;h4 id=&quot;desde-su-creación-t0-hasta-antes-del-momento-tr-1&quot;&gt;Desde su creación, (T&lt;sub&gt;0&lt;/sub&gt;), hasta antes del momento (T&lt;sub&gt;r&lt;/sub&gt;).&lt;/h4&gt;

&lt;p&gt;Las historias pueden tener un tamaño muy grande, y esto es lo adecuado, ya que nos interesa que su tamaño sea grande porque, como explicamos más arriba, aún no tenemos información suficiente para reducir su tamaño.&lt;/p&gt;

&lt;p&gt;Además existe mucha incertidumbre sobre qué historias acabarán desarrollándose o no, y por tanto, la probabilidad de desperdiciar tiempo y energía intentando reducir su tamaño es muy alta.&lt;/p&gt;

&lt;p&gt;Por ejemplo podríamos plantear una historia de usuario como la siguiente:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Marketing necesita informes para evaluar el impacto de las acciones realizadas.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aunque esta historia abarca mucha funcionalidad, al menos deja abierta los tipos de informes que podrían aportar más valor. Así, si más tarde cambian las necesidades o se descubren otros informes que aportan más valor, ese cambio de decisión no afecta a la historia.&lt;/p&gt;

&lt;p&gt;De hecho, si, de antemano, reducimos todas las historias lo más posible acabaremos en lo que se conoce como el &lt;strong&gt;“user story card hell”&lt;/strong&gt;&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;en-tr-1&quot;&gt;En T&lt;sub&gt;r&lt;/sub&gt;.&lt;/h4&gt;

&lt;p&gt;En este momento se da una tensión entre dos necesidades.&lt;/p&gt;

&lt;p&gt;Por un lado queremos reducir el tamaño de la historia de usuario para que las reuniones con el equipo sean lo más efectivas posible, pero, no queremos reducirlo demasiado para no cerrar opciones antes de examinarla en la reunión de refinamiento.&lt;/p&gt;

&lt;p&gt;El riesgo de reducir demasiado el tamaño de la historia de usuario antes de la reunión de refinamiento es que podríamos crear un &lt;a href=&quot;https://en.wikipedia.org/wiki/Framing_effect_(psychology)&quot;&gt;efecto de framing&lt;/a&gt; en el equipo, que reduciría su capacidad para proponer alternativas más creativas o económicamente más interesantes.&lt;/p&gt;

&lt;p&gt;Acertar con el tamaño adecuado en el momento, T&lt;sub&gt;r&lt;/sub&gt;, es a veces complicado porque hay que equilibrar los dos objetivos en tensión, conseguir una reunión eficiente y no cerrar demasiado las opciones. Nuestro consejo es no preocuparse en exceso para no caer en parálisis por análisis. Con el tiempo iremos aprendiendo a equilibrar ambos objetivos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, la anterior historia podría convertirse en la siguiente:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Como usuario del Departamento de Marketing, quiero generar informes de los cambios de planes de nuestros suscriptores para evaluar el impacto de las campañas.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lo que reduciría el tamaño de la historia de usuario pero dejando aún algunas opciones abiertas.&lt;/p&gt;

&lt;h4 id=&quot;poco-antes-de-td-1&quot;&gt;Poco antes de T&lt;sub&gt;d&lt;/sub&gt;.&lt;/h4&gt;

&lt;p&gt;En este momento, el contexto cambia de manera radical. Ahora lo que buscamos es que las historias sean lo más pequeñas posibles.&lt;/p&gt;

&lt;p&gt;Los motivos por los que tratamos de reducir las historias de usuario lo más posible son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Entregar valor lo antes posible&lt;/strong&gt;, de forma que el usuario pueda obtener beneficio de una parte lo antes posible. En este sentido las historias de usuario representarían posibles incrementos de valor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Reducir riesgo&lt;/strong&gt;. Con incrementos pequeños de funcionalidad se reduce el riesgo de desviarnos de lo que espera el usuario, al tiempo, que se reduce el riesgo de incurrir en retrabajo y el de introducir errores.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Ciclos de feedback cortos&lt;/strong&gt;. Los incrementos pequeños de funcionalidad nos permiten experimentar, aprender, ajustar nuestras prioridades y tomar mejores decisiones.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Siguiendo con el ejemplo anterior, la historia puede convertirse en la siguiente:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;Como usuario del Departamento de Marketing, quiero generar un informe de los aumentos de planes contratados en los últimos 30 días para evaluar el impacto de las campañas mensuales”.&lt;/div&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;* Mostrar fecha del informe.&lt;/div&gt;
  &lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding:5px&quot;&gt;* Mostrar la cantidad total de planes que han aumentado.&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;En este ejemplo se reduce el tamaño de la historia al detallar que sólo nos preocupa cuándo hay un aumento de planes contratados (y no un descenso), la fecha del informe y la cantidad total de planes contratados en ese periodo.&lt;/p&gt;

&lt;p&gt;En futuras versiones, podríamos plantearnos refinar este aspecto pero ahora Marketing ya está obteniendo al menos un informe que le proporcionará una buena parte del valor que inicialmente necesitaba.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;Hemos visto cómo tenemos que ajustar el tamaño y nivel de detalle de las historias de usuario a medida que nos vamos acercando al momento en que se desarrolla una historia.&lt;/p&gt;

&lt;p&gt;Desde su creación, (T&lt;sub&gt;0&lt;/sub&gt;), hasta antes del momento (T&lt;sub&gt;r&lt;/sub&gt;), cuando hay mayor incertidumbre, las historias son más grandes y menos detalladas, lo que permite mantener opciones abiertas y evitar esfuerzos innecesarios.&lt;/p&gt;

&lt;p&gt;Poco antes de una reunión de refinamiento (T&lt;sub&gt;r&lt;/sub&gt;), las historias que vamos a presentar en ella deben ajustarse en tamaño y detalle lo suficiente como para fomentar discusiones efectivas, pero evitando cerrar nuestras opciones prematuramente.&lt;/p&gt;

&lt;p&gt;Finalmente, al llegar al momento del desarrollo (T&lt;sub&gt;d&lt;/sub&gt;), las historias deben ser pequeñas y bastante detalladas para eliminar ambigüedades, reducir riesgos y permitir entregas incrementales de valor.
También vimos una relación importante, que detallar una historia de usuario es lo que permite reducir su tamaño, ya que el detalle aclara el alcance y esto facilita dividirla, si fuera necesario, en historias más pequeñas sin perder claridad.
En futuros posts seguiremos profundizando en este tema dando heurísticas que pueden ayudarnos a escribir historias de usuario adecuadas para dos de los momentos importantes que hemos comentado en este post: antes de presentar la historia en una una reunión de refinamiento (T&lt;sub&gt;r&lt;/sub&gt;), y justo antes de empezar a desarrollarla, (T&lt;sub&gt;d&lt;/sub&gt;).&lt;/p&gt;

&lt;h2 id=&quot;serie-historias-de-usuario&quot;&gt;Serie Historias de Usuario.&lt;/h2&gt;
&lt;p&gt;Este post es parte de una serie sobre Historias de usuario:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;¿Tamaño y nivel de detalle adecuados para una historia de usuario?.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2025/10/flujo-refinar-hu-en-tc&quot;&gt;Nuestro flujo de decisión para refinar Historias de Usuario poco antes de empezar a desarrollarla&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2026/03/detallando-historias&quot;&gt;Detallando historias de usuario para acotarlas y reducir su ambigüedad&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h2&gt;
&lt;p&gt;Nos gustaría darle las gracias a &lt;a href=&quot;https://www.pexels.com/es-es/@ivan-samkov/&quot;&gt;Ivan Samkov&lt;/a&gt; por la foto del post.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Este paso no tiene porque ser realizado de manera explícita pero es un paso implícito que se produce cuando intentamos hacer la historia más pequeña. Podríamos acabar con una sóla historia y a la vez implícitamente estar descartando otras opciones que podrían estar presentes en la historia inicial.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Sería posible que sólo nos preocupara ordenar por fecha de compra y entonces la historias quedaría directamente como “Quiero ordenar productos por fecha de compra”.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] También es posible que haya un cambio de prioridad pero la probabilidad de que esto ocurra es mayor cuanto más alejado estamos de T&lt;sub&gt;d&lt;/sub&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Un efecto, que hemos observado, que puede estar escondiendo el posible desperdicio generado, es caer en el sesgo del &lt;a href=&quot;https://en.wikipedia.org/wiki/Sunk_cost&quot;&gt;coste hundido&lt;/a&gt; para no tirar a la basura la inversión que ya hemos hecho, aunque haya otra solución mejor.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Es curioso observar que para reducir el problema del olvido, se suele anotar más detalles. Eso provoca que aumente el tiempo invertido en un momento en el que la incertidumbre es mayor y por tanto aumentan las posibilidades de haber hecho trabajo innecesario.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6]  El principio del último momento responsable, También es un problema tomar decisiones de manera tardía porque pueden generar pérdida de oportunidades y retrabajo para terceros.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Algunos autores usan el concepto de condiciones de satisfacción o rules para hablar de los criterios de aceptación por diferentes motivos. Mike Cohn prefiere utilizar &lt;a href=&quot;https://www.mountaingoatsoftware.com/blog/clarifying-the-relationship-between-definition-of-done-and-conditions-of-sa&quot;&gt;condiciones de satisfacción&lt;/a&gt; y en &lt;a href=&quot;https://cucumber.io/blog/bdd/example-mapping-introduction/&quot;&gt;Example Mapping&lt;/a&gt; se utiliza el concepto de &lt;strong&gt;Rules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Card, Conversation, Confirmation son 3 aspectos esenciales enunciados por Ron Jeffries en su &lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;artículo de 2001&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] Liz Keogh documenta una serie de patrones conversacionales al trabajar con ejemplos que pueden ser muy útiles para explorar los ejemplos en &lt;a href=&quot;https://lizkeogh.com/2011/09/22/conversational-patterns-in-bdd/&quot;&gt;Conversational patterns in BDD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] Si bien existen criterios para juzgar si el tamaño de una historia es adecuado, como por ejemplo &lt;a href=&quot;https://xp123.com/invest-in-good-stories-and-smart-tasks/&quot;&gt;INVEST&lt;/a&gt;, no todos los criterios son aplicables, o si lo son, no con el mismo peso en cada uno de los momentos, t&lt;sub&gt;0&lt;/sub&gt;, t&lt;sub&gt;r&lt;/sub&gt; y t&lt;sub&gt;d&lt;/sub&gt;. Además, si fuera necesario, hay diversas técnicas para dividir historias de usuario, o, en algunos casos, incluso fusionarlas.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] “Story card hell is when you have 300 story cards and you have to keep track of them all” from &lt;a href=&quot;https://www.jamesshore.com/v2/presentations/2005/beyond-story-cards&quot;&gt;Beyond Story Cards: Agile Requirements Collaboration&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2025-06-24T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/06/size-and-details-in-user-stories</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/06/size-and-details-in-user-stories</guid>
        </item>
      
    
      
        <item>
          <title>Usando conjuntamente ApprovalsJs y StrykerJS en WebStorm</title>
          <description>&lt;h2 id=&quot;introducción&quot;&gt;Introducción.&lt;/h2&gt;
&lt;p&gt;En un &lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;post anterior&lt;/a&gt; mostramos como integrar &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; con &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para poder aplicar la técnica de &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master&lt;/a&gt; necesitamos generar nuestro &lt;strong&gt;golden master&lt;/strong&gt; mediante un proceso de &lt;strong&gt;muestreo&lt;/strong&gt; (&lt;strong&gt;sampling&lt;/strong&gt;)&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez tenemos escritos los tests aplicando golden master, (o approval testing que como dijimos en el post anterior, facilita la aplicación de la técnica de &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master&lt;/a&gt;) debemos evaluar lo bien que estos tests protegen el comportamiento existente contra posibles regresiones.&lt;/p&gt;

&lt;p&gt;Para ello usaremos herramientas de cobertura y de mutation testing&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; que son capaces de detectar posibles debilidades de nuestros tests 
que nos lleven a refinarlos hasta que consigamos proteger el comportamiento contra regresiones de forma satisfactoria (el significado de “de forma satisfactoria” dependerá tanto del comportamiento como del tipo de aplicación en cuestión).&lt;/p&gt;

&lt;p&gt;La siguiente figura resume este proceso de refinamiento:&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 60%&quot;&gt;
&lt;img src=&quot;/assets/refining_the_golden_master.png&quot; alt=&quot;Refining golden master tests.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Refinando los tests de golden master (del material del curso Cambiando Legacy).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Por tanto, es muy recomendable usar herramientas de approval testing y mutation testing de manera conjunta.&lt;/p&gt;

&lt;p&gt;En el caso que se aborda en este post necesitábamos aplicar estas técnicas para caracterizar un código escrito en TypeScript.&lt;/p&gt;

&lt;p&gt;Como ya describimos en un &lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;post anterior&lt;/a&gt; usamos &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; para escribir nuestros tests  de golden master.&lt;/p&gt;

&lt;p&gt;Para mutation testing en TypeScript la herramienta que más nos gusta usar es &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt;.
En este post, veremos cómo configurar estas dos herramientas para que trabajen juntas de manera eficiente, dentro de &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;el-problema&quot;&gt;El problema.&lt;/h2&gt;

&lt;p&gt;Como ya explicamos, en un approval test cada vez que se produce una diferencia entre el resultado aprobado (esperado) y el obtenido durante el test, &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; lanza una herramienta de comparación visual para que el desarrollador pueda evaluar más fácilmente  la discrepancia entre los dos resultados&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esto, sin embargo, se vuelve un problema cuando usamos la técnica de mutation testing que se basa en introducir mutaciones (básicamente regresiones) deliberadas en el código fuente para comprobar si los tests fallan como se espera.&lt;/p&gt;

&lt;p&gt;Una herramienta de mutation testing generará un montón de copias del código introduciendo una mutación en cada copia (el mutante), y luego ejecutará nuestros tests contra cada una de esas copias.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 80%&quot;&gt;
&lt;img src=&quot;/assets/how_mutation_testing_works.png&quot; alt=&quot;how mutation testing tools work.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Funcionamiento de una herramienta de mutation testing (del material del curso Cambiando Legacy).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Si los tests fallan al ejecutarlos contra un mutante es que nos protegen contra ese tipo de regresión, si no fallan puede que hayamos descubierto una debilidad en nuestros tests&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cuando usamos una herramienta de mutation testing, si nuestros tests no son terribles de partida, para la mayoría de los mutantes nuestros tests deberían fallar.&lt;/p&gt;

&lt;p&gt;El problema es que, si resulta que el test que falla es un approval test lanzará la herramienta de diff que hayamos configurada y se parará la ejecución hasta que interactuemos con dicha herramienta. 
Por tanto, el flujo de un approval test de lanzar un diff tool cuando el test falla no es compatible con mutation testing y se convierte en un obstáculo.&lt;/p&gt;

&lt;p&gt;Hay que decir que este posible problema ya esta resuelto de entrada cuando hemos usado approval testing junto con mutation testing en Java y .Net, pero, por desgracia, no es así cuando usamos &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; y &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt; con WebStorm.&lt;/p&gt;

&lt;p&gt;Cuando ejecutamos una herramienta de mutation testing debemos evitar que se lance la herramienta de diff cada vez que un test de approval falle nos interesa para que el proceso pueda ejecutarse sin intervención humana.&lt;/p&gt;

&lt;h2 id=&quot;nuestra-solución&quot;&gt;Nuestra solución.&lt;/h2&gt;

&lt;p&gt;Para resolver esta incompatibilidad entre mutation testing y approval testing necesitaremos informar de alguna manera al &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt; del contexto en que se están ejecutando los tests, básicamente, saber si estamos usando mutation testing o no.&lt;/p&gt;

&lt;p&gt;Consultando en el código fuente de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenericDiffReporterBase&lt;/code&gt; de la que &lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;extendimos para crear nuestro reporter para WebStorm&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;, vemos que tiene un método público &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isReporterAvailable(): boolean&lt;/code&gt; que se usa como clausula de guarda en el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canReportOn(fileName: string): boolean&lt;/code&gt; de la interfaz &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;, si &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isReporterAvailable&lt;/code&gt; devuelve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canReportOn&lt;/code&gt; también devolverá &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;, y eso evitará que abra la ventana de la herramienta de diff de WebStorm.&lt;/p&gt;

&lt;p&gt;Sabiendo esto sobreescribimos el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isReporterAvailable(): boolean&lt;/code&gt; en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/b57a4b25bd7191db94440e752ea08d8b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Para que funcione como queremos sólo nos faltaría setear la variable de entorno de node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MUTATION_TESTING&lt;/code&gt; a true cada vez que ejecutamos &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt;. Esto se puede conseguir utilizando la propiedad &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;command&quot;&lt;/code&gt; del objeto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;commandRunner&quot;&lt;/code&gt; en el fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stryker.conf.json&lt;/code&gt;, que configura &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt;, de la siguiente manera:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/753f422a3ef80b207788767295f1f42a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Con esta modificación de la configuración de &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt; y con el cambio en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt; que mostramos  más arriba se consigue que la herramienta de diff nunca se lance mientras se ejecutan los tests de mutación.&lt;/p&gt;

&lt;p&gt;La variable de entorno &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MUTATION_TESTING&lt;/code&gt; sólo existirá mientras dure la ejecución de los tests de mutación, de forma que, si, en cualquier momento, ejecutamos tests que no sean de mutación recuperamos el comportamiento de lanzar la herramienta de diff configurada cada vez que un test de approval falle.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;

&lt;p&gt;Utilizando tests de mutación con &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt; en WebStorm para intentar refinar unos tests de golden master que usaban &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; nos encontramos la sorpresa de que la herramienta de diff se lanzaba cada vez que los tests fallaba, lo cuál ocurría casi para cada uno de los mutantes generados haciendo que en la práctica la ejecución de los tests de mutación dejara de ser automática.&lt;/p&gt;

&lt;p&gt;Para resolverlo tuvimos que consultar el código fuente de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;ApprovalsJS&lt;/a&gt; para saber como modificar nuestra implementación de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt; para WebStorm, y modificar la configuración de &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js/blob/master/README.md&quot;&gt;StrykerJS&lt;/a&gt; para introducir una variable de entorno de &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node&lt;/a&gt; que informara a nuestro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reporter&lt;/code&gt; de que los tests de approval se estaban ejecutando en el contexto de una ejecución de los tests de mutación.&lt;/p&gt;

&lt;p&gt;Esperamos que esta solución les pueda servir para no caer en el mismo problema en que caímos nosotros.&lt;/p&gt;

&lt;h3 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h3&gt;

&lt;p&gt;Nos gustaría agradecer a las empresas que hasta ahora han confiado en nosotros para ayudar a sus equipos a mejorar cómo trabajan con su código legacy. Ya hemos dado cuatro ediciones del curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt; que han tenido muy buen feedback y nos han permitido refinar su contenido.&lt;/p&gt;

&lt;p&gt;Por último, también nos gustaría darle las gracias a &lt;a href=&quot;https://www.pexels.com/es-es/@introspectivedsgn/&quot;&gt;Erik Mclean&lt;/a&gt; por la foto del post.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Existen diferentes estrategias de sampling para generar nuestro golden master (input y output). 
Las principales estrategias de sampling son:&lt;/p&gt;

&lt;p&gt;a. Faking input &amp;amp; recording output.&lt;/p&gt;

&lt;p&gt;b. Generating random input &amp;amp; recording output.&lt;/p&gt;

&lt;p&gt;c. Recording production input &amp;amp; output.&lt;/p&gt;

&lt;p&gt;Profundizamos en el refinamiento en nuestro curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] En nuestro blog puedes encontrar &lt;a href=&quot;https://codesai.com/publications/categories/#Mutation%20Testing&quot;&gt;otros posts interesantes sobre mutation testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] En &lt;a href=&quot;https://codesai.com/posts/2025/05/approvasls-en-webstorm&quot;&gt;Integrando ApprovalsJS con WebStorm&lt;/a&gt; explicamos cómo hicimos para que ApprovalJs usará la herramienta de diff de WebStorm.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] No siempre es así, hay mutantes supervivientes (para los que nuestros tests no fallan) que no son relevantes para mejorar los tests, sino que podrían ser debidos, o bien, a código muerto, o bien, a código innecesario. Para profundizar en esta idea lee nuestro post &lt;a href=&quot;https://codesai.com/posts/2025/04/mutantes-relevantes&quot;&gt;Mutantes relevantes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Ver el código de &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/e570bc10678ef9aba2cff304b4fbc0477c011740/lib/Reporting/GenericDiffReporterBase.ts#L30C3-L30C22&quot;&gt;isReporterAvailable&lt;/a&gt; y &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/e570bc10678ef9aba2cff304b4fbc0477c011740/lib/Reporting/GenericDiffReporterBase.ts#L49&quot;&gt;canReportOn&lt;/a&gt; en la clase &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/master/lib/Reporting/GenericDiffReporterBase.ts&quot;&gt;GenericDiffReporterBase&lt;/a&gt;, y la interface &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/master/lib/Core/Reporter.ts&quot;&gt;Reporter&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2025-06-06T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/06/usando-approvalsjs-y-strykerjs-en-webstorm</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/06/usando-approvalsjs-y-strykerjs-en-webstorm</guid>
        </item>
      
    
      
        <item>
          <title>&quot;Isolated&quot; test means something very different to different people!</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;A concept that we find very useful both when we do TDD and when introducing tests into legacy code are the &lt;strong&gt;FIRS properties&lt;/strong&gt; (&lt;strong&gt;F&lt;/strong&gt;ast, &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable, &lt;strong&gt;S&lt;/strong&gt;elf-validating), which are used to describe an ideal unit test. This concept originates from the &lt;strong&gt;FIRST&lt;/strong&gt; acronym, which describes ideal unit tests in the context of TDD, where the T stands for &lt;strong&gt;T&lt;/strong&gt;imely&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is what we mean by &lt;strong&gt;F&lt;/strong&gt;ast, &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable and &lt;strong&gt;S&lt;/strong&gt;elf-validating tests:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;F&lt;/strong&gt;ast: they should execute so quickly that we never feel the need to delay running them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;I&lt;/strong&gt;solated: they should produce the same results regardless of the order in which they are executed. This means they do not depend on one another in any way, whether directly or indirectly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;R&lt;/strong&gt;epeatable: they should be deterministic, their results should not change if the tested behavior and environment remain unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;S&lt;/strong&gt;elf-validating: they should pass or fail automatically, without requiring human intervention to determine the outcome. This property is essential for enabling test automation.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the distinct contexts of TDD and retrofitting tests in legacy code, the same &lt;strong&gt;FIRS properties&lt;/strong&gt; fulfill different roles, guiding us in designing testable units in the former and uncovering testability problems in the latter&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When retrofitting tests in legacy code, violations of &lt;strong&gt;FIRS properties&lt;/strong&gt; highlight dependencies that impede testing, referred to as &lt;strong&gt;awkward collaborations&lt;/strong&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. These &lt;strong&gt;awkward collaborations&lt;/strong&gt; point to the dependencies we need to break using &lt;strong&gt;dependency-breaking techniques&lt;/strong&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; to enable the introduction of unit tests.&lt;/p&gt;

&lt;p&gt;In the case of integration tests, it is sufficient to focus on violations of the &lt;strong&gt;I&lt;/strong&gt;solated, &lt;strong&gt;R&lt;/strong&gt;epeatable and &lt;strong&gt;S&lt;/strong&gt;elf-validating properties. Dependencies that violate the &lt;strong&gt;R&lt;/strong&gt;epeatable and &lt;strong&gt;S&lt;/strong&gt;elf-validating properties require &lt;strong&gt;dependency-breaking techniques&lt;/strong&gt; to address them, whereas violations of the &lt;strong&gt;I&lt;/strong&gt;solated property can often be alternatively resolved through other approaches, such as test-specific &lt;a href=&quot;http://xunitpatterns.com/test%20fixture%20-%20xUnit.html&quot;&gt;fixtures&lt;/a&gt; or configuration changes.&lt;/p&gt;

&lt;p&gt;In the context of TDD, violations of the &lt;strong&gt;FIRS properties&lt;/strong&gt; are a key heuristic to identify the collaborations that we need to push outside the unit under test. These &lt;strong&gt;awkward collaborations&lt;/strong&gt; will be simulated with test doubles in our unit tests.&lt;/p&gt;

&lt;p&gt;Notice that, when doing TDD, identifying &lt;strong&gt;awkward collaborations&lt;/strong&gt; is more challenging because we must infer them from the requirements. In contrast, in legacy code, we can identify them more easily since they are visible in the code and manifest through the testability problems they cause.&lt;/p&gt;

&lt;p&gt;Identifying &lt;strong&gt;awkward collaborations&lt;/strong&gt; is, therefore, an important skill for designing testable code. In this sense, &lt;strong&gt;FIRS properties&lt;/strong&gt; serve as a valuable guideline for defining the boundaries of a unit, helping us develop testable code.&lt;/p&gt;

&lt;h2 id=&quot;it-seems-isolated-test-means-something-very-different-to-different-people&quot;&gt;It seems “isolated test” means something very different to different people!&lt;/h2&gt;

&lt;figure style=&quot;margin:auto; width: 70%&quot;&gt;
&lt;img src=&quot;/assets/isolated_meme.jpg&quot; alt=&quot;Isolated. You keep using that word. I do not think it means what you think it means.&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;If you read the original definition of &lt;strong&gt;isolated&lt;/strong&gt; from &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;Agile in a Flash:  F.I.R.S.T.&lt;/a&gt; 
you will notice that it is different from what we expressed in the previous section.&lt;/p&gt;

&lt;p&gt;We said that for us &lt;strong&gt;isolated&lt;/strong&gt; meant that “the test should produce the same results regardless of the order in which they are executed. 
This means they do not depend on one another in any way, whether directly or indirectly”.&lt;/p&gt;

&lt;p&gt;In the definition of &lt;strong&gt;isolated&lt;/strong&gt; from &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;Agile in a Flash:  F.I.R.S.T.&lt;/a&gt;, the flash card states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Isolated: Failure reasons become obvious.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Later, in the explanation, they elaborate on what this means (the emphasis in bold was added by us):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Isolated: Tests isolate failures. A developer should never have to reverse-engineer tests or the code being tested to know what went wrong. Each test class name and test method name with the text of the assertion should state exactly what is wrong and where. If a &lt;strong&gt;test&lt;/strong&gt; does not &lt;strong&gt;isolate failures&lt;/strong&gt;, it is best to replace that test with smaller, more-specific tests.&lt;/p&gt;

  &lt;p&gt;A good unit test has &lt;strong&gt;a laser-tight focus on a single effect or decision in the system under test&lt;/strong&gt;. And that system under test tends to be a single part of a single method on a single class (hence “unit”). &lt;strong&gt;Tests must not have any order-of-run dependency&lt;/strong&gt;. They should pass or fail the same way in suite or when run individually. Each suite should be re-runnable (every minute or so) even if tests are renamed or reordered randomly. &lt;strong&gt;Good tests interfere with no other tests in any way&lt;/strong&gt;. &lt;strong&gt;They impose their initial state without aid from other tests&lt;/strong&gt;. &lt;strong&gt;They clean up after themselves&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt;’s &lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt; summarizes this as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Isolated - tests don’t rely upon either other in any way, including indirectly. Each test isolates one failure mode only.”&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For us &lt;strong&gt;isolated&lt;/strong&gt;, in the context of identifying awkward collaborations, means that tests should be isolated from each other, which, in practice, means that they can not share any mutable state or resource. Our definition is less restrictive than Ottinger’s one. We are choosing to consider only one aspect of their definition, that  “tests interfere with no other tests in any way”, and not the other one, “tests have a single reason to fail”, (we’ll comment more about this other aspect below).&lt;/p&gt;

&lt;p&gt;We think that what we mean by &lt;strong&gt;isolated&lt;/strong&gt; aligns with the definition Kent Beck provides in his book &lt;a href=&quot;https://www.oreilly.com/library/view/test-driven-development/0321146530/&quot;&gt;Test Driven Development: By Example&lt;/a&gt;. In the section &lt;em&gt;Isolated Test&lt;/em&gt; (page 125) of the chapter &lt;em&gt;Test-Driven Development Patterns&lt;/em&gt;, he writes:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“How should the running of tests affect one another? Not at all.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[…] the main lesson […] tests should be able to ignore one another completely.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“One convenient implication of isolated tests is that the tests are order independent.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moreover, in his more recent work &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt; he defines &lt;strong&gt;isolated&lt;/strong&gt; as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“tests should return the same results regardless of the order in which they are run”&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having said that, there is another desirable property for tests in &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt; which is interesting for this discussion, &lt;strong&gt;specificity&lt;/strong&gt;, which Kent Beck explains as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Specific: if a test fails, the cause of the failure should be obvious.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We think that, the second aspect of &lt;strong&gt;isolated&lt;/strong&gt; in Ottinger’s definition, &lt;strong&gt;having a single reason to fail&lt;/strong&gt;, corresponds to the highest possible level of Beck’s specificity. It seems that what Ottinger means by &lt;strong&gt;isolated&lt;/strong&gt; includes two of the desirable properties of tests described by Beck’s &lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;the property of returning the same results regardless of the order in which they are run (being &lt;strong&gt;isolated&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;the property of test failures having an obvious cause” (being &lt;strong&gt;specific&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having a single reason to fail is still a highly desirable property which we also take into account while writing test cases. It can help to compose independent behaviours and to avoid overspecifying some tests&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, in the context of identifying &lt;strong&gt;awkward collaborations&lt;/strong&gt;, we have found Beck’s definition of &lt;strong&gt;isolated&lt;/strong&gt; to be more useful, 
in order to avoid the &lt;strong&gt;considering-the-class-as-the-unit trap&lt;/strong&gt;, and to teach the use of test doubles as isolation tools, 
which is how they are mostly employed in the classic style of TDD.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;We showed how the &lt;strong&gt;FIRS properties&lt;/strong&gt; can be valuable in both TDD and retrofitting tests in legacy code, guiding developers toward creating more testable and maintainable code.&lt;/p&gt;

&lt;p&gt;We explored how the concept of &lt;strong&gt;isolated&lt;/strong&gt; tests differs depending on the author. While Kent Beck’s definition emphasizes independence between tests, ensuring they produce consistent results regardless of execution order, the definition from &lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;F.I.R.S.T in Agile in a Flash&lt;/a&gt; also states that tests should have a single reason to fail. We believe this intertwines Beck’s definition of &lt;strong&gt;isolation&lt;/strong&gt; with another test property: &lt;strong&gt;specificity&lt;/strong&gt;, with having a single reason to fail representing the highest level of &lt;strong&gt;specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We think that, both Beck’s and Ottinger’s definitions of &lt;strong&gt;isolated&lt;/strong&gt; are valuable. However, Beck’s version aligns more closely with what we mean by &lt;strong&gt;isolated&lt;/strong&gt; in the context of identifying &lt;strong&gt;awkward collaborations&lt;/strong&gt;. For us, Beck’s definition has proven especially useful while identifying &lt;strong&gt;awkward collaborations&lt;/strong&gt;, to avoid the &lt;strong&gt;trap of considering the class as the unit&lt;/strong&gt;, and to &lt;strong&gt;teach&lt;/strong&gt; how to use &lt;strong&gt;test doubles&lt;/strong&gt; as isolation tools.&lt;/p&gt;

&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;

&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;“Isolated” test means something very different to different people!&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;
&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;, 
&lt;a href=&quot;https://www.linkedin.com/in/franiglesias/&quot;&gt;Fran Iglesias Gómez&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio De La Torre&lt;/a&gt; 
for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://imgflip.com/&quot;&gt;imgflip&lt;/a&gt; for their &lt;a href=&quot;https://imgflip.com/memegenerator/294538550/Hi-Res-Inconceivable-Inigo-Montoya&quot;&gt;Inconceivable Iñigo Montoya Meme Generator&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://agileinaflash.blogspot.com/2009/02/first.html&quot;&gt;F.I.R.S.T in Agile in a Flash&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/jefflangr/&quot;&gt;Jeff Langr&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/pragmatic-programmers/unit-tests-are-first-fast-isolated-repeatable-self-verifying-and-timely-a83e8070698e&quot;&gt;Unit Tests Are FIRST: Fast, Isolated, Repeatable, Self-Verifying, and Timely&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/jefflangr/&quot;&gt;Jeff Langr&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt;, &lt;a href=&quot;https://agileotter.blogspot.com/&quot;&gt;Tim Ottinger&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://jbazuzicode.blogspot.com/2016/07/pure-unit-test-vs-firstness.html&quot;&gt;“pure unit test” vs. “FIRSTness”&lt;/a&gt;, &lt;a href=&quot;https://jay.bazuzi.com/&quot;&gt;Jay Bazuzi&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/test-driven-development/0321146530/&quot;&gt;Test Driven Development: By Example&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/@kentbeck_7670/test-desiderata-94150638a4b3&quot;&gt;Test Desiderata&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HApI2cspQus&quot;&gt;Test Desiderata 8/12: Tests Should Be Isolated (from each other)&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8lTfrCtPPNE&quot;&gt;Test Desiderata 10/12: Tests Should be Specific&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.google.com/document/d/1C85clIy1ZoytjeogApsjCQTdX5aiwo6YcqgCFn8lh20/edit?usp=sharing&quot;&gt;Notes on isolated tests according to Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.google.com/document/d/1QCkJ4WeC4cXy95xXHAEP6iVzTp_1KE5vpTqJVeDJz_I/edit?usp=sharing&quot;&gt;Notes on specific tests according to Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/UnitTest.html&quot;&gt;Unit Test&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/nonDeterminism.html&quot;&gt;Eradicating Non-Determinism in Tests&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=dTRKCXC0JFg&quot;&gt;Princess Bride, “You keep using that word. I do not think it means what you think it means.”&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See also &lt;a href=&quot;https://jay.bazuzi.com/&quot;&gt;Jay Bazuzi&lt;/a&gt;’s post &lt;a href=&quot;https://jbazuzicode.blogspot.com/2016/07/pure-unit-test-vs-firstness.html&quot;&gt;“pure unit test” vs. 
“FIRSTness”&lt;/a&gt; to learn more about categorizing tests according to their &lt;strong&gt;FIRSness&lt;/strong&gt; (removing the &lt;strong&gt;T&lt;/strong&gt;) which can be useful when working with legacy code, or when testing after.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] We delve into this topic in depth in our &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;TDD training&lt;/a&gt; and our &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] See &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Fowler&lt;/a&gt;’s article &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt; to see where the term &lt;strong&gt;awkward collaboration&lt;/strong&gt; comes from.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] See our post &lt;a href=&quot;https://codesai.com/posts/2024/03/mindmup-breaking-dependencies&quot;&gt;Classifying dependency-breaking techniques&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Aside from summarizing very well what “Isolated” means to them, &lt;a href=&quot;https://agileotter.blogspot.com/2021/09/first-idea-that-ran-away-from-home.html&quot;&gt;FIRST: an idea that ran away from home&lt;/a&gt;  dives into the history of how the FIRST properties came about and how their meaning has blurred over time. Plus, it includes a list of sources that discuss FIRST, highlighting changes made by each source, like in the &lt;a href=&quot;https://en.wikipedia.org/wiki/Telephone_game&quot;&gt;telephone game&lt;/a&gt;, and noting that some don’t even give credit to the original authors.&lt;/p&gt;

&lt;p&gt;It also refers to another article published by &lt;a href=&quot;https://pragprog.com/&quot;&gt;Pragmatic Programmers&lt;/a&gt; as the origin of the acronym &lt;a href=&quot;https://medium.com/pragmatic-programmers/unit-tests-are-first-fast-isolated-repeatable-self-verifying-and-timely-a83e8070698e&quot;&gt;Unit Tests Are FIRST: Fast, Isolated, Repeatable, Self-Verifying, and Timely&lt;/a&gt;, which we believe explains FAST better and even includes code examples.&lt;/p&gt;

&lt;p&gt;Finally, it explains the &lt;strong&gt;value of writing tests first&lt;/strong&gt; and criticize writing them afterwards.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] &lt;a href=&quot;https://www.linkedin.com/in/ian-cooper-2b059b/&quot;&gt;Ian Cooper&lt;/a&gt;, in his talk &lt;a href=&quot;https://www.youtube.com/watch?v=EZ05e7EMOLM&quot;&gt;TDD, where did it all go wrong&lt;/a&gt; states that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“For Kent Beck, [a unit test] is a test that runs in isolation from other tests.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;“[…] NOT to be confused with the classical unit test definition of targeting a module.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;”A lot of issues with TDD is people misunderstanding isolation as class isolation […]”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We talked about this frequent misunderstanding in our post &lt;a href=&quot;https://codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class&quot;&gt;The class is not the unit in the London school style of TDD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] We may write about this in a future post.&lt;/p&gt;

</description>
          <pubDate>2025-06-03T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/06/isolated-test-something-different-to-different-people</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/06/isolated-test-something-different-to-different-people</guid>
        </item>
      
    
      
        <item>
          <title>Integrando ApprovalsJS con WebStorm</title>
          <description>&lt;h3 id=&quot;contexto&quot;&gt;Contexto.&lt;/h3&gt;

&lt;p&gt;En nuestro curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt; exploramos diferentes maneras de caracterizar código legado. Una de las que explicamos es approval testing.&lt;/p&gt;

&lt;p&gt;Approval testing facilita la aplicación de la técnica de &lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/surviving-legacy-code-with-golden-master-and-sampling&quot;&gt;Golden Master&lt;/a&gt;, 
aportando una herramienta que nos ayuda con algunos de los pasos más complicados y/o engorrosos de la técnica de Golden Master:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;la comparación entre el resultado real y el aprobado (golden master),&lt;/li&gt;
  &lt;li&gt;la visualización de las diferencias entre ellos (si las hay), y&lt;/li&gt;
  &lt;li&gt;el proceso de aprobación de un nuevo resultado válido (actualización del golden master).&lt;/li&gt;
&lt;/ul&gt;

&lt;figure style=&quot;margin:auto; width: 60%&quot;&gt;
&lt;img src=&quot;/assets/approval_test.png&quot; alt=&quot;Approval testing flow.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Flujo de approval testing (del material del curso Cambiando Legacy).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;En una edición reciente del curso que tuvo Typescript como lenguaje conductor, utilizamos la librería &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; para demostrar cómo aplicar approval testing&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; es la versión para Node de la herramienta &lt;a href=&quot;https://approvaltests.com/&quot;&gt;Approvals&lt;/a&gt; que está disponible en varios lenguajes, siendo probablemente la de Java la más popular y mantenida.&lt;/p&gt;

&lt;h3 id=&quot;el-problema-o-más-bien-nuestras-necesidades&quot;&gt;El problema o, más bien, nuestras necesidades.&lt;/h3&gt;

&lt;p&gt;Aunque también se puede usar &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt; en el curso, el IDE que utilizamos para nuestras demos es &lt;a href=&quot;https://www.jetbrains.com/webstorm/&quot;&gt;WebStorm&lt;/a&gt; porque es el que nosotros solemos usar para desarrollar.&lt;/p&gt;

&lt;p&gt;Cuando existe una diferencia entre el resultado real y el resultado aprobado, &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; lanza una diff tool para facilitarnos la detección de las diferencias entre ambos resultados, y así ayudarnos a determinar el origen de dichas diferencias.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://approvaltests.com/&quot;&gt;Approvals&lt;/a&gt; define una abstracción para esta responsabilidad de facilitar la detección de diferencias entre los resultados real y aprobado: el &lt;strong&gt;Report&lt;/strong&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. Dicha abstracción se implementa con adaptadores concretos que utilizan diferentes herramientas de diff.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; viene configurado con una lista de &lt;strong&gt;Reports&lt;/strong&gt; que usa de manera priorizada, es decir, empieza por intentar ejecutar el primer &lt;strong&gt;Report&lt;/strong&gt; de la lista, si lo encuentra y todo va bien usa ese, y si no pasa a intentar ejecutar el siguiente de la lista, y así sucesivamente.&lt;/p&gt;

&lt;p&gt;En nuestro caso, no nos interesaba utilizar (ni siquiera las teníamos instaladas) ninguna de las herramientas de diff configuradas por defecto, (BeyondCompare, Diffmerge, P4merge, Tortoisemerge, etc.), sino que queríamos usar la propia herramienta de diff de WebStorm para no tener que cambiar de contexto y tener una experiencia de desarrollo más fluida&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El problema es que no existía un &lt;strong&gt;Report&lt;/strong&gt; por defecto para trabajar con Webstorm.&lt;/p&gt;

&lt;h3 id=&quot;la-solución-escribir-un-report-para-webstorm&quot;&gt;La solución: escribir un &lt;strong&gt;Report&lt;/strong&gt; para WebStorm.&lt;/h3&gt;

&lt;p&gt;Para cubrir nuestras necesidad de usar la propia herramienta de diff de WebStorm y tener una experiencia de desarrollo más fluida no nos quedó otra que escribir un adaptador de la abstracción &lt;strong&gt;Report&lt;/strong&gt; que use la herramienta de diff de WebStorm.&lt;/p&gt;

&lt;p&gt;Este es el código de nuestro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/dfdb2032924f80d37c5d93f84c2b3c28.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; actualmente puede integrarse  con dos runners, &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; y &lt;a href=&quot;https://mochajs.org/&quot;&gt;Mocha&lt;/a&gt;. Nosotros nos limitamos a hacer funcionar nuestro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt; con Jest porque es el runner que utilizamos en el curso. Si necesitas utilizar WebStorm con Mocha mira la documentación para ver cómo modificarlo.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/WebStormReporter.png&quot; alt=&quot;Ventana de diff de WebStorm abierta por WebStormReporter.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Ventana de diff de WebStorm abierta por WebStormReporter.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Para usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;, basta con llamar en los tests a la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAsJson&lt;/code&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; que exportamos en vez de la función que proporciona Jest.&lt;/p&gt;

&lt;h3 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h3&gt;

&lt;p&gt;Hemos mostrado cómo, gracias a la abstracción &lt;strong&gt;Report&lt;/strong&gt; de  &lt;a href=&quot;https://approvaltests.com/&quot;&gt;Approvals&lt;/a&gt;, se puede conseguir integrar de manera sencilla &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; con Webstorm.&lt;/p&gt;

&lt;p&gt;En un futuro post, hablaremos de qué tuvimos que hacer para poder combinar approval testing y mutation testing de forma integrada dentro Webstorm.&lt;/p&gt;

&lt;h3 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h3&gt;

&lt;p&gt;Nos gustaría agradecer a las tres empresas que hasta ahora han confiado en nosotros para ayudar a sus equipos a mejorar cómo trabajan con su código legacy. Ya hemos dado cuatro ediciones del curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy&lt;/a&gt; que han tenido muy buen feedback y nos han permitido refinar su contenido.&lt;/p&gt;

&lt;p&gt;Por último, también nos gustaría darle las gracias a &lt;a href=&quot;https://www.pexels.com/es-es/@markusspiske/&quot;&gt;Markus Spiske&lt;/a&gt; por la foto del post.&lt;/p&gt;

&lt;h3 id=&quot;notas&quot;&gt;Notas.&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Usamos la versión &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;7.2.3&lt;/code&gt;. Para que no falle la compilación hay que añadir al &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tsconfig.json&lt;/code&gt; la opción &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ìnclude&lt;/code&gt; indicando que sólo chequee los tipos en ficheros dentro de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;, porque hay varios ficheros en &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS&quot;&gt;Approvals JS&lt;/a&gt; que no pasan el chequeo de tipos.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/fc3885b8432a4f733d50c455c8cdd349.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Approvals define toda una serie de &lt;a href=&quot;https://github.com/approvals/ApprovalTests.Java/blob/master/approvaltests/docs/Features.md#main-concepts-for-approvaltests&quot;&gt;abstracciones fundamentales (Writer, Reporter, Namer..)&lt;/a&gt; que permiten extender su comportamiento y adaptarla en caso de que sea necesario.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Además estamos acostumbrados a ella porque la usamos regularmente para resolver conflictos en merges o visualizar cambios en la Local History.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] &lt;a href=&quot;https://github.com/approvals/Approvals.NodeJS/blob/master/lib/Providers/Jest/JestApprovals.ts&quot;&gt;JestApprovals&lt;/a&gt; tiene otros métodos como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verify&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAll&lt;/code&gt;. Nosotros utilizamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAsJson&lt;/code&gt; porque necesitábamos comparar objetos y nos resultaba más cómodo hacerlo usando el formato JSON. Es por esto que sólo nos hemos preocupado de proporcionar una versión de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verifyAsJson&lt;/code&gt; que use nuestro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebStormReporter&lt;/code&gt;.&lt;/p&gt;

</description>
          <pubDate>2025-05-16T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/05/approvasls-en-webstorm</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/05/approvasls-en-webstorm</guid>
        </item>
      
    
      
        <item>
          <title>Mutantes relevantes</title>
          <description>&lt;p&gt;Este post es una traducción al español con algunas mejoras y actualizaciones del post original en inglés &lt;a href=&quot;https://codesai.com/posts/2024/07/relevant-mutants&quot;&gt;Relevant mutants&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;1-introducción&quot;&gt;1. Introducción.&lt;/h3&gt;

&lt;p&gt;Usar mutation testing nos da información sobre la capacidad de detección de errores de nuestros tests, es decir, sobre si las aserciones contenidas en dichos tests son lo suficientemente buenas como para detectar regresiones.&lt;/p&gt;

&lt;p&gt;La técnica de mutation testing se basa en inyectar intencionalmente una regresión en una copia del código, “el mutante”, para después ejecutar los tests contra dicho mutante y verificar si alguno de los tests falla:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Si falla algún test, todo va bien, “los tests han matado al mutante”. Esto significa que nuestros tests nos protegen de ese tipo de regresión.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Si no falla ningún test, “el mutante sobrevive”, y esto podría no ser bueno. Que un mutante sobreviva quiere decir que nuestros tests no nos protegen de que ocurra esa regresión. Es posible que hayamos encontrado algo que debemos mejorar en nuestros tests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutation_testing.png&quot; alt=&quot;Uso de mutation testing.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Uso de mutation testing.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Sin embargo, cuando aplicamos mutation testing no todos los mutantes supervivientes son una señal de debilidades en los tests, este fenómeno es aún más significativo en código legacy.&lt;/p&gt;

&lt;p&gt;Por un lado, es posible que algunos de los supervivientes estén relacionados con la existencia de código muerto, mientras que otros podrían indicar código que es innecesario para producir el comportamiento esperado y, por lo tanto, podría simplificarse&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Es por esto, que debemos analizar cada mutante superviviente para determinar si es relevante o no, y sólo en caso de serlo, escribir nuevos tests para eliminarlo.&lt;/p&gt;

&lt;p&gt;Veámoslo con un ejemplo.&lt;/p&gt;

&lt;h3 id=&quot;2-análisis-de-los-mutantes-supervivientes-en-la-kata-crazy-portfolio&quot;&gt;2. Análisis de los mutantes supervivientes en la kata Crazy Portfolio.&lt;/h3&gt;

&lt;p&gt;La &lt;a href=&quot;https://codesai.com/posts/2024/03/crazy-portfolio-kata&quot;&gt;kata Crazy Portfolio&lt;/a&gt; es una kata para practicar con código heredado que publicamos no hace mucho. Esta kata es compleja porque el código de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Portfolio&lt;/code&gt; además de tener muchas responsabilidades y una lógica condicional compleja, utiliza fechas y zonas horarias y produce side-effects. Por si esto fuera poco existen muchas particiones con sus correspondientes fronteras y algunas invariantes de clase implícitas&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En el &lt;a href=&quot;https://github.com/Codesai/practice_program_ts_audiense/tree/main/09-crazy-portfolio_b&quot;&gt;código&lt;/a&gt; que utilizaremos en este ejemplo ya habíamos escrito tests de caracterización que lograban la máxima cobertura de rama posible. La cobertura de rama no puede ser del 100% porque hay una rama inalcanzable en el código de producción, y porque las &lt;a href=&quot;https://martinfowler.com/bliki/LegacySeam.html&quot;&gt;costuras&lt;/a&gt; que introdujimos usando &lt;a href=&quot;https://www.youtube.com/watch?v=i7NfgsM4VqA&quot;&gt;Extract and Override Call&lt;/a&gt; para romper dependencias y poder testear el código, por supuesto, no se ejecutan en los tests.&lt;/p&gt;

&lt;p&gt;Dependiendo del refactoring que deseemos hacer, podría ser que una cobertura de rama alta no fuera suficiente para comenzar a refactorizar con confianza. Por este motivo decidimos aplicar mutation testing usando &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js&quot;&gt;Stryker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El resultado de aplicar mutation testing fue que 36 de 160 mutantes sobrevivieron, con lo que, parecía que tendríamos mucho trabajo de mejora en nuestros tests agregando nuevos casos de test para eliminar todos esos mutantes, y quizás algunos de ellos no serían fáciles de eliminar.&lt;/p&gt;

&lt;p&gt;Si analizamos los mutantes supervivientes, veremos que realmente no había tantos mutantes que eliminar.&lt;/p&gt;

&lt;p&gt;Los mutantes supervivientes se pueden clasificar en las siguientes categorías:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Mutantes en código muerto.&lt;/li&gt;
  &lt;li&gt;Mutantes en costuras.&lt;/li&gt;
  &lt;li&gt;Mutantes en código que no se utiliza desde los tests debido a las costuras.&lt;/li&gt;
  &lt;li&gt;Mutantes en código superfluo que no indican debilidades en los tests.&lt;/li&gt;
  &lt;li&gt;Mutantes que sí indican debilidades en los tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Analicemos las distintas categorías una por una.&lt;/p&gt;

&lt;h4 id=&quot;2-1-mutantes-en-código-muerto&quot;&gt;2. 1. Mutantes en código muerto.&lt;/h4&gt;

&lt;p&gt;Esta categoría incluye todas las mutaciones contenidas en la rama no accesible que está en la línea 60, que ya habíamos identificado cuando escribimos los tests de caracterización.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irelevant_mutants_in_dead_code.png&quot; alt=&quot;Los mutantes supervivientes en código muerto son irrelevantes.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Los mutantes supervivientes en código muerto son irrelevantes.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Estos mutantes supervivientes son obviamente irrelevantes.&lt;/p&gt;

&lt;h4 id=&quot;2-2-mutantes-en-costuras&quot;&gt;2. 2. Mutantes en costuras.&lt;/h4&gt;

&lt;p&gt;Todos los mutantes supervivientes dentro de las costuras que introdujimos al romper dependencias para poder testear el código, como por ejemplo, el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createDate&lt;/code&gt; que se muestra en el siguiente fragmento del informe de Stryker, no son relevantes porque el código incluido en las costuras no se ejecuta en los tests.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irrelevant_mutants_in_seams.png&quot; alt=&quot;Los mutantes supervivientes dentro de costuras son irrelevantes.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Los mutantes supervivientes dentro de costuras son irrelevantes.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Lo mismo sucede con los mutantes que sobreviven dentro de las otras costuras: los métodos protegidos: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;formatDate&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAssetLines&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;displayMessage&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getNow&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;2-3-mutantes-en-código-que-no-se-utiliza-desde-los-tests-debido-a-las-costuras&quot;&gt;2. 3. Mutantes en código que no se utiliza desde los tests debido a las costuras.&lt;/h4&gt;

&lt;p&gt;En este grupo encontramos la mutación que sobrevive dentro del constructor de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Portfolio&lt;/code&gt;,&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irrelevant_mutants_in_unused_code_due_to_seams.png&quot; alt=&quot;Los mutantes supervivientes en código que no se utiliza desde los tests debido a las costuras son irrelevantes.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Los mutantes supervivientes en código que no se utiliza desde los tests debido a las costuras son irrelevantes.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Como introdujimos una costura para poder obtener los activos del portafolio sin tener que leer el archivo en los tests unitarios, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAssetLines&lt;/code&gt;, el campo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portfolioCsvPath&lt;/code&gt; no se utiliza para nada, por lo tanto, el mutante superviviente mostrado en la figura anterior no es una mutación relevante.&lt;/p&gt;

&lt;h5 id=&quot;sobre-las-categorías-que-hemos-analizado-hasta-ahora&quot;&gt;Sobre las categorías que hemos analizado hasta ahora.&lt;/h5&gt;

&lt;p&gt;Los mutantes supervivientes en las tres categorías que hemos visto hasta ahora se pueden ignorar de forma rápida y segura porque no proporcionan ninguna pista sobre cómo mejorar los tests o el código de producción. Se trata de mutantes supervivientes código no ejercitado por los tests.&lt;/p&gt;

&lt;p&gt;Las cosas no son tan sencillas con el resto de mutantes supervivientes, que caen en las dos categorías que nos falta por analizar.&lt;/p&gt;

&lt;p&gt;Tendremos que examinarlos uno por uno para ver si realmente indican debilidades en nuestros tests, o si apuntan a código de producción superfluo que podría simplificarse.&lt;/p&gt;

&lt;p&gt;Veamos las dos categorías restantes.&lt;/p&gt;

&lt;h4 id=&quot;2-4-mutantes-en-código-superfluo-que-no-indican-debilidades-en-los-tests&quot;&gt;2. 4. Mutantes en código superfluo que no indican debilidades en los tests.&lt;/h4&gt;

&lt;p&gt;Analicemos los ejemplos más interesantes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Caso 1: Mutaciones que sobreviven en la línea 29.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observen esta mutación que cambia un operador de división por un operador de producto:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_changing_division_in_before_or_after_boolean_expression_1.png&quot; alt=&quot;Mutación superviviente que cambia el operador / por el operador * en la línea 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutación superviviente que cambia un operador / por un operador * en la línea 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;o esta otra mutación que cambia un operador de producto por un operador de división:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_changing_division_in_before_or_after_boolean_expression_2.png&quot; alt=&quot;Mutación que cambia un operador de producto por un operador de división en la línea 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutación superviviente que cambia un operador de producto por un operador de división en la línea 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Hay varias mutaciones similares más en la misma línea.&lt;/p&gt;

&lt;p&gt;Estas mutaciones que reemplazan el operador de división por el operador de producto parecen muy confusas y, al principio, pueden resultar incluso desconcertantes. ¿Por qué sobreviven?&lt;/p&gt;

&lt;p&gt;Para comprenderlo, debemos analizar con más detalle la condición que se está mutando y su significado.&lt;/p&gt;

&lt;p&gt;Al hacerlo, vemos que lo único relevante para que la condición &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.floor(asset.getDate().getTime() - now.getTime() / (1000 * 60 * 60 * 24)) &amp;lt; 0&lt;/code&gt; sea verdadera o falsa es el signo de la diferencia entre los dos tiempos en milisegundos: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset.getDate().getTime() - now.getTime()&lt;/code&gt;. 
El resto de la expresión, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1000 * 60 * 60 * 24)&lt;/code&gt;, es simplemente un número positivo (se trata un factor de conversión para pasar de milisegundos a días) que no cambiará el signo de dicha diferencia de tiempo, y, por lo tanto, no cambiará la evaluación de la expresión booleana completa,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.floor(la_diferencia_de_tiempos / el_numero_positivo) &amp;lt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esto quiere decir que todos esos mutantes que cambian los operadores &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; no están señalando ningún tipo de debilidad en nuestros tests. Lo que realmente indican es la existencia de código de producción innecesario, en este caso la conversión de milisegundos a días, que podríamos simplificar&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;, quedando la siguiente condición: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.floor(asset.getDate().getTime() - now.getTime()) &amp;lt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esta simplificación (que sólo haríamos una vez tuviésemos tests más fuertes que ya eliminen todos los mutantes relevantes) sería suficiente para eliminar todos los mutantes relacionados con código superfluo en la línea 29.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Case 2. Mutaciones que sobreviven en la línea 27.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_in_mapping_to_value_objects.png&quot; alt=&quot;Mutación superviviente en la creación de un value object en la línea 27.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutación superviviente en la creación de un value object en la línea 27.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Esta mutación superviviente hace que nunca se creen objetos de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PricelessValue&lt;/code&gt; (la condición es sustituida por un false), y aún así los tests siguen pasando. ¿ Cómo puede ocurrir esto?&lt;/p&gt;

&lt;p&gt;Que estos mutantes sobrevivan quiere decir que, o bien, tenemos alguna debilidad en los tests, o bien, que la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PricelessValue&lt;/code&gt; no es necesaria para el comportamiento que los tests están protegiendo. Para entender qué opción es la correcta debemos preguntarnos cómo es que estas mutaciones han sobrevivido.&lt;/p&gt;

&lt;p&gt;Si miramos con atención el código, nos daremos cuenta de que estas mutaciones sobreviven porque la clase derivada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PricelessValue&lt;/code&gt; no se utiliza en absoluto en el código. 
En el código de producción sólo se está utilizando el getter de la clase base de la jerarquía, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MeasurableValue&lt;/code&gt;, y por lo tanto, toda la jerarquía de herencia es superflua. La causa detrás de este problema es la &lt;a href=&quot;https://wiki.c2.com/?FeatureEnvySmell&quot;&gt;feature envy&lt;/a&gt; contra la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Asset&lt;/code&gt; que existe en el código actual, es más &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Asset&lt;/code&gt; es una &lt;a href=&quot;https://web.archive.org/web/20240530214936/https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=22&quot;&gt;data class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;De nuevo, estos mutantes no son relevantes para mejorar nuestros tests y no tenemos que perder el tiempo intentando matarlos ahora.&lt;/p&gt;

&lt;p&gt;Cuando ya tengamos  mejores tests que eliminen todas las mutaciones relevantes, podremos refactorizar el código para eliminar la &lt;a href=&quot;https://wiki.c2.com/?FeatureEnvySmell&quot;&gt;feature envy&lt;/a&gt; rampante contra la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Asset&lt;/code&gt;,  y decidir si es necesario mantener o no la jerarquía &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MeasurableValue&lt;/code&gt;. Por tanto, una buena asignación de responsabilidades eliminaría las mutaciones de la línea 27 que hemos comentado.&lt;/p&gt;

&lt;h4 id=&quot;5-mutantes-que-sí-indican-debilidades-en-los-tests&quot;&gt;5. Mutantes que sí indican debilidades en los tests.&lt;/h4&gt;

&lt;p&gt;Sólo uno de los mutantes de la línea 29 es relevante para mejorar nuestros tests, el que cambia el operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; por el operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_before_or_after_boolean_expression.png&quot; alt=&quot;Mutante superviviente en la línea 29 que cambia  el operador &amp;lt; por  el operador &amp;lt;=.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutante superviviente en la línea 29 que cambia  el operador &amp;lt; por  el operador &amp;lt;=.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;La supervivencia de este mutante nos está indicando que nuestros tests no están ejercitando correctamente los valores alrededor de una frontera entre diferentes comportamientos o &lt;a href=&quot;https://en.wikipedia.org/wiki/Equivalence_partitioning&quot;&gt;particiones&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hay otros mutantes supervivientes similares al anterior que también indican problemas al testear valores alrededor de una frontera, por ejemplo los de las líneas 32 y 46 que se presentan a continuación:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_value_lower_boundary.png&quot; alt=&quot;Mutante superviviente en la línea 32 relacionado con problemas al probar valores alrededor de una frontera.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutante superviviente en la línea 32 relacionado con problemas al probar valores alrededor de una frontera.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_value_upper_boundary.png&quot; alt=&quot;Mutante superviviente en la línea 46 relacionado con problemas al probar valores alrededor de una frontera.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutante superviviente en la línea 46 relacionado con problemas al probar valores alrededor de una frontera.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Otro ejemplo de un mutante superviviente que puede indicar una debilidad en nuestros tests es el de la línea 22 que se muestra a continuación:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_in_exception_message.png&quot; alt=&quot;Mutante superviviente en la línea 22 relacionado con no chequear el mensaje de una excepción.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mutante superviviente en la línea 22 relacionado con no chequear el mensaje de una excepción.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Si examinamos los test, veremos que lo que estamos comprobando es si se lanza una excepción cuando la fecha tiene un formato incorrecto, pero no estamos comprobando el mensaje de la excepción. En este caso, para eliminar este mutante habría que hacer que los tests se acoplen al texto concreto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;”wrong date”&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;En nuestra opinión, el mensaje concreto de error es un detalle volátil y acoplar los tests a él sería una especificación excesiva que aumentaría innecesariamente la fragilidad de los tests. Para evitarlo decidimos ignorar dicho mutante.&lt;/p&gt;

&lt;h3 id=&quot;conclusiones&quot;&gt;Conclusiones.&lt;/h3&gt;

&lt;p&gt;Hemos mostrado un ejemplo de cómo no todos los mutantes supervivientes indican debilidades en nuestros tests. De los 36 mutantes supervivientes originales, solo 13 acabaron siendo relevantes para mejorar nuestros tests&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; (optamos por ignorar el mutante superviviente relacionado con el mensaje de error). En este caso, los 13 mutantes relevantes están relacionados con fronteras entre comportamientos que los tests no están chequeando correctamente.&lt;/p&gt;

&lt;p&gt;Como los mutantes supervivientes, a veces, no son fáciles de eliminar&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;, está muy bien saber identificar aquellos que no son relevantes para mejorar los tests.&lt;/p&gt;

&lt;p&gt;Matar 13 mutantes es una tarea mucho menos abrumadora que matar a 36, pero tuvimos que invertir tiempo en analizar los 36 mutantes para ver si eran relevantes o no. Lo bueno es que la mayoría de los mutantes descartados e irrelevantes fueron fáciles de identificar: los relacionados con la existencia de código muerto&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt; y los relacionados con la introducción de costuras.&lt;/p&gt;

&lt;p&gt;También discutimos otra categoría de mutantes supervivientes que, si bien no señalan la necesidad de mejorar los tests, son una señal de código que podría ser innecesario para lograr el comportamiento deseado. Esta información puede ser muy interesante para guiar refactorizaciones posteriores, una vez hayamos mejorado los tests eliminando los mutantes relevantes.&lt;/p&gt;

&lt;p&gt;Espero que este ejemplo detallado les pueda resultar útil al analizar los resultados de aplicar mutation testing.&lt;/p&gt;

&lt;h3 id=&quot;agradecimientos&quot;&gt;Agradecimientos.&lt;/h3&gt;

&lt;p&gt;Me gustaría agradecer a &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/in/rub%C3%A9n-d%C3%ADaz-mart%C3%ADnez-b9276395/&quot;&gt;Rubén Díaz&lt;/a&gt; por revisar borradores de este post.&lt;/p&gt;

&lt;p&gt;También agradecemos a los desarrolladores de Audiense por haber sido los beta testers de la &lt;a href=&quot;https://codesai.com/posts/2024/03/crazy-portfolio-kata&quot;&gt;kata Crazy Portfolio&lt;/a&gt; como parte de las &lt;strong&gt;sesiones de práctica deliberada&lt;/strong&gt; que llevamos haciendo desde hace unos años. Siempre es un placer trabajar con ustedes.&lt;/p&gt;

&lt;p&gt;Por último, también me gustaría darle las gracias a &lt;a href=&quot;https://www.pexels.com/es-es/@cgoulao/&quot;&gt;Carlos Machado&lt;/a&gt; por la foto del post.&lt;/p&gt;

&lt;h3 id=&quot;notas&quot;&gt;Notas.&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Estos dos tipos de falso positivo (mutantes irrelevantes) están directamente relacionados con los code smells &lt;a href=&quot;https://luzkan.github.io/smells/dead-code&quot;&gt;Dead Code&lt;/a&gt; y &lt;a href=&quot;https://web.archive.org/web/20231129150643/https://www.informit.com/articles/article.aspx?p=2952392&amp;amp;seqNum=15&quot;&gt;Speculative Generality&lt;/a&gt; que &lt;a href=&quot;https://xp123.com/&quot;&gt;William Wake&lt;/a&gt; clasifica bajo la categoría &lt;em&gt;Unnecessary Complexity&lt;/em&gt;. Ver nuestro post &lt;a href=&quot;https://codesai.com/posts/2022/09/code-smells-taxonomies-and-catalogs&quot;&gt;De taxonomías y catálogos de code smells&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Solíamos usar una versión simplificada de esta kata en nuestro curso &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Cambiando Legacy Code&lt;/a&gt;, pero al final decidimos cambiarla por otra kata un poco más sencilla.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Ya hablamos de mutantes supervivientes que señalan código redundante en un post anterior: &lt;a href=&quot;https://codesai.com/posts/2022/02/mutation-testing&quot;&gt;Mutando para simplificar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Los 13 mutantes supervivientes relevantes se encuentran en las líneas 29 (1), 32 (2), 46 (2), 70 (1), 71 (2), 76 (1), 77 (2) y 83 (2).&lt;/p&gt;

&lt;p&gt;Los mutantes supervivientes en las líneas 32, 46, 77 y 83 señalan fronteras entre comportamientos que los tests están ignorando por completo (por ese motivo puede sobrevivir una mutación que elimina completamente la condición), mientras que los mutantes supervivientes en las líneas 29, 70 y 76 indican fronteras entre comportamientos que los tests sólo están  probando parcialmente.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Probar bien las fronteras entre diferentes comportamientos y, por lo tanto, eliminar mutantes relacionados con ellas se vuelve mucho más fácil si se conocen los conceptos de on-point y off-point de una frontera. Este conocimiento proporciona un método sistemático para eliminar este tipo de mutantes. En el material actualizado de &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;nuestra formación de TDD&lt;/a&gt; enseñamos a analizar y testear correctamente valores de frontera.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] Nuestra recomendación es que, antes de usar una herramienta de mutation testing, utilicen una herramienta de cobertura para detectar código no cubierto por los tests y código muerto, ya que, los resultados de las herramientas de cobertura son mucho más fáciles de analizar que los resultados de las herramientas de mutation testing.&lt;/p&gt;

</description>
          <pubDate>2025-04-25T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/04/mutantes-relevantes</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/04/mutantes-relevantes</guid>
        </item>
      
    
      
        <item>
          <title>Sprouting or wrapping?</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;In situations in which we really don’t have time to &lt;strong&gt;cover &amp;amp; modify&lt;/strong&gt;, we can use techniques that allow us to write tested code somewhere else and use it from existing code doing minimal changes to it. These techniques must be used carefully because, even though they enable us to add tested code, its usage is not tested. This is not ideal but it’s still much better than giving up and using &lt;strong&gt;edit &amp;amp; pray&lt;/strong&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are two such techniques: &lt;strong&gt;wrapping&lt;/strong&gt; and &lt;strong&gt;sprouting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We have noticed that sometimes people find it difficult to know when to apply one or the other.&lt;/p&gt;

&lt;p&gt;This post will only focus on discussing when to apply each technique&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;sprouting-or-wrapping&quot;&gt;Sprouting or wrapping?&lt;/h2&gt;

&lt;p&gt;We choose either &lt;em&gt;sprouting&lt;/em&gt; or &lt;em&gt;wrapping&lt;/em&gt; depending on the location where the requested change needs to be applied.&lt;/p&gt;

&lt;h3 id=&quot;when-to-use-sprouting&quot;&gt;When to use sprouting.&lt;/h3&gt;

&lt;p&gt;If after identifying where we need to add a new behaviour, the change point is in the middle of an existing behaviour, we will use &lt;em&gt;sprouting&lt;/em&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 70%&quot;&gt;
&lt;img style=&quot;margin:auto; width: 60%; heigth: 60%&quot; src=&quot;/assets/posts/2025-03-sprouting-or-wrapping/change_points_for_sprouting.png&quot; alt=&quot;Changes for which we use sprouting (figure from Changing Legacy Code training.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Changes for which we use sprouting (figure from &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;when-to-use-wrapping&quot;&gt;When to use wrapping.&lt;/h3&gt;

&lt;p&gt;If the new behaviour happens either before or/and after an existing behaviour, i .e., the change point is before or/and after an existing behaviour, we will use &lt;em&gt;wrapping&lt;/em&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 70%&quot;&gt;
&lt;img src=&quot;/assets/posts/2025-03-sprouting-or-wrapping/change_points_for_wrapping.png&quot; alt=&quot;Changes for which we use wrapping (figure from Changing Legacy Code training.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Changes for which we use wrapping (figure from &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary.&lt;/h2&gt;

&lt;p&gt;In this short post we have discussed when to apply &lt;em&gt;wrapping&lt;/em&gt; or &lt;em&gt;sprouting&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We’ve seen how we will apply &lt;em&gt;wrapping&lt;/em&gt; or &lt;em&gt;sprouting&lt;/em&gt; depending on in which part of the existing behaviour the new one is going to happen.&lt;/p&gt;

&lt;p&gt;Once we identify the &lt;em&gt;change points&lt;/em&gt;, if they are before or/and after the existing behaviour, we’ll use &lt;em&gt;wrapping&lt;/em&gt;. If not, it means that the &lt;em&gt;change point&lt;/em&gt; is in the middle of the existing behaviour, and then we’ll use &lt;em&gt;sprouting&lt;/em&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 70%&quot;&gt;
&lt;img src=&quot;/assets/posts/2025-03-sprouting-or-wrapping/sprouting_wrapping_decision_flow.png&quot; alt=&quot;Decision flow to choose wrapping or sprouting (figure from Changing Legacy Code training.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Decision flow to choose wrapping or sprouting (figure from &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Remember, &lt;em&gt;wrapping&lt;/em&gt; and &lt;em&gt;sprouting&lt;/em&gt; are techniques that allow placing changes in new tested code without having to cover existing behaviour. As such, they are shortcuts for when we don’t have enough time to &lt;em&gt;cover &amp;amp; modify&lt;/em&gt;. This is not ideal but it’s still much better than giving up and using &lt;em&gt;edit &amp;amp; pray&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for revising drafts of this post.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@greta-hoffman/&quot;&gt;Greta Hoffman&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.c2.com/?WorkingEffectivelyWithLegacyCode&quot;&gt;Working Effectively with Legacy Code book&lt;/a&gt;, &lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] If you are not familiar with the terms &lt;em&gt;cover &amp;amp; modify&lt;/em&gt;, &lt;em&gt;edit &amp;amp; pray&lt;/em&gt;, &lt;em&gt;wrapping&lt;/em&gt; or &lt;em&gt;sprouting&lt;/em&gt;, you may want to read &lt;a href=&quot;https://wiki.c2.com/?WorkingEffectivelyWithLegacyCode&quot;&gt;Working Effectively with Legacy Code book&lt;/a&gt; or have a look at our &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] If you don’t know how to apply them, have a look at the following links for quick recipes, &lt;a href=&quot;https://gist.github.com/trikitrok/e3aa609f476ff2dc00ffbbc2673ce79e&quot;&gt;wrap method&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/trikitrok/80768c8b969472b272dd8167fa3094f3&quot;&gt;wrap class&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/trikitrok/49a888731ffd4decf9d45ca74f0facb4&quot;&gt;sprout method&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/trikitrok/dfab2b265f8790e5d7d1f4364d42f12a&quot;&gt;sprout class&lt;/a&gt;, or, even better, read chapter 6, “I Don’t Have Much Time and I Have to Change It” of &lt;a href=&quot;https://wiki.c2.com/?WorkingEffectivelyWithLegacyCode&quot;&gt;Working Effectively with Legacy Code book&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2025-03-14T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/03/sprouting-or-wrapping</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/03/sprouting-or-wrapping</guid>
        </item>
      
    
      
        <item>
          <title>The class is not the unit in the London school style of TDD</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;h4 id=&quot;a-dangerous-misconception-considering-that-the-class-is-the-unit-in-unit-testing&quot;&gt;A dangerous misconception: considering that the class is the unit in unit testing.&lt;/h4&gt;

&lt;p&gt;Considering that the class is the unit in unit testing has terrible effects. If we follow this idea, we’ll use test doubles to isolate the class under test from any class that collaborates with it (its collaborators). This will produce tests that are highly coupled with implementation details, and therefore very brittle (high structure-sensitiveness)&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/unit_is_the_class.png&quot; alt=&quot;Considering the class as the unit...&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Considering the class as the unit...&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This brittleness will make those refactorings affecting interfaces to which our tests are coupled more expensive (they will take more time&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;), as we’d be forced to change the tests as well. This increase in cost will hinder refactoring.&lt;/p&gt;

&lt;p&gt;Many problems when using test doubles are caused solely by this misconception. Thankfully it seems to be receding, as more developers are starting to understand that the unit in unit testing is the behavior and not the class. This understanding helps to produce less structure-sensitive tests which don’t hinder refactoring.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/unit_is_not_the_class.png&quot; alt=&quot;The class is not the unit.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;The class is not the unit.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;the-surviving-misconception-considering-that-the-class-is-the-unit-in-the-london-school-or-mockist-style-of-tdd&quot;&gt;The surviving misconception: considering that the class is the unit in the London School or Mockist style of TDD.&lt;/h4&gt;

&lt;p&gt;Recently, we have noticed many videos, posts and even books &lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; that affirm that the, so called, mockist style of TDD considers that the class is the unit in unit testing.&lt;/p&gt;

&lt;p&gt;Unfortunately this other widespread misconception is making developers, either apply the mockist style of TDD completely wrong (testing every class in isolation from its collaborator), or choose not to use it altogether to avoid the class-is-the-unit problems we described before.&lt;/p&gt;

&lt;p&gt;In the remainder of this post, we will show that &lt;em&gt;the mockist style of TDD does not consider the class is the unit in unit testing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In our discussion below, we will use the book &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt; (GOOS) by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt; as the reference for the mockist style of TDD.&lt;/p&gt;

&lt;h2 id=&quot;the-class-is-not-the-unit-in-the-mockist-style-of-tdd&quot;&gt;The class is not the unit in the mockist style of TDD.&lt;/h2&gt;

&lt;h4 id=&quot;exhibit-1-values--objects&quot;&gt;Exhibit 1: Values &amp;amp; Objects.&lt;/h4&gt;

&lt;p&gt;In the section &lt;em&gt;Values and Objects&lt;/em&gt; (chapter 2: &lt;em&gt;Test-Driven Development with Objects&lt;/em&gt;) of the GOOS book its authors distinguish between two concepts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Values&lt;/strong&gt;, which “model unchanging quantities or measurements” (think of &lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;Value Objects&lt;/a&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Objects&lt;/strong&gt;, which “have an identity, might change state over time, and model computational processes”.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the word “object” is used in the GOOS book, they refer only to the second concept.&lt;/p&gt;

&lt;h5 id=&quot;dont-double-values&quot;&gt;Don’t double values!!&lt;/h5&gt;

&lt;p&gt;As its title says, the section &lt;em&gt;Don’t Mock Values&lt;/em&gt; (chapter 20: &lt;em&gt;Listening to the Tests&lt;/em&gt;) recommends that we do not use test doubles to simulate values in tests.&lt;/p&gt;

&lt;p&gt;The GOOS authors say even more:&lt;/p&gt;

&lt;p&gt;“There’s no point in writing mocks for values (which should be immutable anyway). Just create an instance and use it.”&lt;/p&gt;

&lt;p&gt;This recommendation in itself shows how the idea of isolating each class by using test doubles of every class that collaborates with the class under test has never been a part of the mockist style.&lt;/p&gt;

&lt;p&gt;Likely, the confusion may have arisen because both concepts, values and objects, are implemented by the same language construct in most OO languages: the class.&lt;/p&gt;

&lt;p&gt;Even though some authors acknowledge the distinction between values and objects, they still that the class is the unit in the mockist style of TDD&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. However, we view this claim as a contradiction.&lt;/p&gt;

&lt;p&gt;There are more ideas in the GOOS book that refute the false belief of considering the class is the unit in the mockist style of TDD.&lt;/p&gt;

&lt;h4 id=&quot;exhibit-2-internals-vs-peers&quot;&gt;Exhibit 2: Internals vs Peers.&lt;/h4&gt;

&lt;p&gt;For the GOOS book authors not all the collaborators of an object are considered “real collaborators”.&lt;/p&gt;

&lt;p&gt;In the section &lt;em&gt;Internals vs Peers&lt;/em&gt; (chapter 6: &lt;em&gt;Object-Oriented Style&lt;/em&gt;), they distinguish two types of collaborators:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Peers&lt;/strong&gt; (“real collaborators”).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Internals&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure style=&quot;margin:auto; width: 50%&quot;&gt;
&lt;img src=&quot;/assets/posts/unit_is_the_class/internals_vs_peers.png&quot; alt=&quot;Internals vs Peers from Mock Roles Not Object States talk.&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Internals vs Peers from &lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk.&lt;/a&gt;&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Sadly, this distinction between &lt;em&gt;internals&lt;/em&gt; and &lt;em&gt;peers&lt;/em&gt; is probably one of the less understood concepts in the GOOS book.&lt;/p&gt;

&lt;h5 id=&quot;recognizing-peers&quot;&gt;Recognizing peers.&lt;/h5&gt;

&lt;p&gt;The GOOS book authors consider that an object’s peers are “objects with single responsibilities”, i. e., following the &lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html&quot;&gt;single responsibility principle&lt;/a&gt;, that can be categorized (loosely) into three types of relationship.&lt;/p&gt;

&lt;p&gt;Peers (real collaborators) stereotypes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Dependencies: services that the object needs from its environment so that it can fulfill its responsibilities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Notifications: other parts of the system that need to know when the object changes state or performs an action.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Adjustments or Policies: objects that tweak or adapt the object’s behaviour to the needs of the system (think &lt;a href=&quot;https://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;Strategy Pattern&lt;/a&gt;).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any collaborator that is not a peer would be considered an internal.&lt;/p&gt;

&lt;p&gt;They only consider these stereotypes as heuristics to help us think about the design, not as hard rules. Later in the book, in the section &lt;em&gt;Where Do Objects Come From?&lt;/em&gt; (chapter 7: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;), they explain other heuristics that we can apply to discover an object’s peers: &lt;em&gt;”Breaking Out”&lt;/em&gt;, &lt;em&gt;“Budding Off”&lt;/em&gt; and &lt;em&gt;”Bundling Up”&lt;/em&gt;. We’ll talk about these techniques in a future post.&lt;/p&gt;

&lt;p&gt;In their talk  &lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States&lt;/a&gt;, Freeman and Pryce provide an excellent explanation of the concepts of internals and peers when discussing the &lt;em&gt;“The test exposes internal implementation details of my object”&lt;/em&gt; test smell.&lt;/p&gt;

&lt;h5 id=&quot;dont-use-test-doubles-for-internals&quot;&gt;Don’t use test doubles for internals!!&lt;/h5&gt;

&lt;p&gt;Identifying an object’s peers is crucial to minimize the coupling of tests to implementation details, since internal objects are not intended to be simulated in tests:&lt;/p&gt;

&lt;p&gt;“We should [only] mock an object’s peers—its dependencies, notifications, and adjustments […]—but not its internals” (chapter 7: &lt;em&gt;Achieving Object-Oriented Design&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;In our tests we will only use test doubles to simulate the behaviors (roles, responsibilities) that the behavior we are testing depends on, not the classes it depends on. This is related to the recommendation “mock roles, not objects”. And those depended-on behaviors are the peers of an object.&lt;/p&gt;

&lt;p&gt;In our opinion, internals should not be injected from the outside; instead, they should be created within the constructors of the objects they belong to.&lt;/p&gt;

&lt;p&gt;The reason to both not using test doubles to simulate internals, and creating them within the constructors of the objects they belong to is to avoid tests “knowing” they exist, thus removing any coupling between them.&lt;/p&gt;

&lt;p&gt;This is an important difference about internals and peers: peers have behaviours interesting enough to be “known” and documented by the tests, whereas internals are not even “known” by the tests.&lt;/p&gt;

&lt;h2 id=&quot;what-is-the-unit-in-the-mockist-style-of-tdd-then&quot;&gt;What is the unit in the mockist style of TDD then?&lt;/h2&gt;

&lt;p&gt;We hope that, by now, we have managed to show that the class is not the unit in the mockist style of TDD. What does the mockist style of TDD TDD consider the unit then?&lt;/p&gt;

&lt;p&gt;Just like the classic style of TDD, the mockist style of TDD also considers behavior as the unit in unit testing&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;. And, as we have seen, a behaviour might be implemented by 1 or N classes, but that is only an implementation detail.&lt;/p&gt;

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

&lt;p&gt;The purpose of this post was to dispel a common misconception about the mockist style of TDD that states that the class is the unit in the mockist style of TDD.&lt;/p&gt;

&lt;p&gt;In some cases, this misconception comes from not having read or not having understood the GOOS book well.&lt;/p&gt;

&lt;p&gt;In some other cases, we think that, sadly, this idea of the class-is-the-unit is used as part of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Straw_man&quot;&gt;straw men&lt;/a&gt; intended to criticize the mockist style of TDD by saying that, all the maintainability problems associated with the class being the unit, are produced by using the mockist style of TDD.&lt;/p&gt;

&lt;p&gt;In any case, by dispeling this common misconception, we hope to facilitate better discussions about the mockist style of TDD trade-offs and enable its more effective application.&lt;/p&gt;

&lt;h4&gt;Update 2025/09/29:&lt;/h4&gt;

&lt;p&gt;Added another distinction between internals and peers: tests know about peers, whereas they ignore that internals exist.&lt;/p&gt;

&lt;h2 id=&quot;the-tdd-test-doubles-and-object-oriented-design-series&quot;&gt;The TDD, test doubles and object-oriented design series.&lt;/h2&gt;

&lt;p&gt;This post is part of a series about TDD, test doubles and object-oriented design:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The class is not the unit in the London school style of TDD&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/06/isolated-test-something-different-to-different-people&quot;&gt;“Isolated” test means something very different to different people!&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/07/heuristics-to-determine-unit-boundaries&quot;&gt;Heuristics to determine unit boundaries: object peer stereotypes, detecting effects and FIRS-ness&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-to-improve-cohesion&quot;&gt;Breaking out to improve cohesion (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2025/11/breaking-out-refactoring-the-tests&quot;&gt;Refactoring the tests after a “Breaking Out” (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2026/02/bundling-up&quot;&gt;Bundling up to reduce coupling and complexity (peer detection techniques)&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/emmanuel-valverde-ramos/&quot;&gt;Emmanuel Valverde Ramos&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/franiglesias/&quot;&gt;Fran Iglesias Gómez&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/marabesi/&quot;&gt;Marabesi Matheus&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@wwarby/&quot;&gt;William Warby&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.manning.com/books/unit-testing&quot;&gt;Unit Testing Principles, Practices, and Patterns&lt;/a&gt;, &lt;a href=&quot;https://enterprisecraftsmanship.com/&quot;&gt;Vladimir Khorikov&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20090807004827/http://msdn.microsoft.com/en-ca/magazine/dd882516.aspx&quot;&gt;Test-Driven Design Using Mocks And Tests To Design Role-Based Objects &lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/%F0%9F%92%BBisaiah-perumalla-8537563/&quot;&gt;Isaiah Perumalla&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://xunitpatterns.com/DOC.html&quot;&gt;Depended-on component (DOC)&lt;/a&gt;, &lt;a href=&quot;http://xunitpatterns.com/gerardmeszaros.html&quot;&gt;Gerard Meszaros&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jmock.org/oopsla2004.pdf&quot;&gt;Mock roles, not objects&lt;/a&gt;,  &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;, Tim Mackinnon and Joe Walnes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Mock-Objects-Nat-Pryce-Steve-Freeman/&quot;&gt;Mock Roles Not Object States talk&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/RoleInterface.html&quot;&gt;Role Interface&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=QponGU3QgUA&quot;&gt;Rookie Mistake - Testing All The Parts&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5GGk9dv8DVs&quot;&gt;Rookie Mistake - Mock Abuse&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://qafoo.com/blog/111_injectables_newables.html&quot;&gt;Injectables vs. Newables&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/tobiasschlitt/&quot;&gt;Tobias Schlitt&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;Test Desiderata 2/12 Tests Should be Structure-Insensitive&lt;/a&gt;, &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Kent Beck&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20230607222852/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/natpryce/&quot;&gt;Nat Pryce&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] When we test classes in isolation, the resulting tests will have a high structure-sensitiveness as opposed to the ideal of tests being structure-insensitive (see  &lt;a href=&quot;https://www.youtube.com/watch?v=bvRRbWbQwDU&quot;&gt;Test Desiderata 2/12 Tests Should be Structure-Insensitive&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] If we apply a &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; the test will not break at any moment during the refactoring, but this is more costly than doing a refactoring when the tests are not affected.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Search the internet and you will find multiple examples of the misconception we are addressing in this post.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] This happens in the book &lt;a href=&quot;https://www.manning.com/books/unit-testing&quot;&gt;Unit Testing Principles, Practices, and Patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] The authors of the GOOS book state that we should “Unit-Test Behavior, Not Methods” (chapter 5: &lt;em&gt;Maintaining the Test-Driven Cycle&lt;/em&gt;).&lt;/p&gt;

</description>
          <pubDate>2025-03-03T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/03/mockist-tdd-unit-not-the-class</guid>
        </item>
      
    
      
        <item>
          <title>A case of Shotgun Surgery</title>
          <description>&lt;p&gt;This post is an English translation of the original post: &lt;a href=&quot;https://codesai.com/posts/2022/09/un-caso-de-shotgun-surgery&quot;&gt;Un caso de Shotgun Surgery&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Some time ago we were collaborating with a client whose product relied heavily on &lt;a href=&quot;https://en.wikipedia.org/wiki/Search_engine_optimization&quot;&gt;Search engine optimization&lt;/a&gt; (SEO). In general, SEO is usually an important area to focus on, but for this client, SEO represented a significant source of income and was therefore critical to their success.&lt;/p&gt;

&lt;p&gt;When search engines analyze a page, there are two key aspects our system needs to determine, the indexing and the canonical of that page:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Indexing: it determines whether a page should be indexed or not by the search engine.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Canonicalization: it specifies the canonical URL of similar pages to avoid penalties for duplicate content.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that product, SEO was not only a significant source of revenue but also quite complex. Decisions about indexing and canonical URLs depended on factors such as location, search types, and the number of results. This complexity was inherent to the domain problem, i. e., its &lt;a href=&quot;https://dzone.com/articles/essential-and-accidental&quot;&gt;essential complexity&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;p&gt;In that legacy system, SEO rules were located in two areas of the application: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; classes.&lt;/p&gt;

&lt;p&gt;Clients viewed these two functionalities through the following interfaces shown below:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/722a14c04fb791df2428f922b6d3144b.js&quot;&gt;&lt;/script&gt;

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

&lt;p&gt;At first glance, based on the names of the interfaces, and, it seemed that the responsibilities were neatly separated. There was one place for deciding whether a page should be indexed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;, and another for calculating its canonical URL, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;. Both came with their own suite of tests that verified their respective behavior independently.&lt;/p&gt;

&lt;p&gt;However, when asked to modify the canonical calculation rules, we were forced to consider and likely modify both the implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;. The same happened when we had to modify the indexing rules. The problem was that changes to one component often required changes to the other.&lt;/p&gt;

&lt;p&gt;Although the interfaces were designed to separate responsibilities and their names aligned with domain concepts, their implementation was not cohesive. Some indexing logic had leaked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;, and some canonical logic had leaked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. The code exhibited a clear case of a code smell known as &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; which is a violation of the &lt;a href=&quot;https://www.thebigbranchtheory.dev/post/single-responsablity/&quot;&gt;Single Responsibility Principle&lt;/a&gt; (SRP). This was a source of &lt;a href=&quot;https://wiki.c2.com/?AccidentalComplexity&quot;&gt;accidental complexity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this specific case, there was a lack of cohesion at the implementation level. Although the axes of change had been correctly identified at the interface level, the responsibilities were scattered across both implementations.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice1_en.png&quot; alt=&quot;A case of shotgun surgery...&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;A case of shotgun surgery...&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;To fix this case of &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; we needed to segregate responsibilities by moving all the indexing logic to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;, and all the canonical logic to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; so that we no longer violate the &lt;a href=&quot;https://www.thebigbranchtheory.dev/post/single-responsablity/&quot;&gt;SRP&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;segregating-the-rules&quot;&gt;Segregating the Rules.&lt;/h2&gt;

&lt;p&gt;If the canonical and indexing logics could be executed in any order, moving the rules would simply involve moving test cases between the tests of each implementation and moving the corresponding code using &lt;a href=&quot;https://refactoring.com/catalog/moveFunction.html&quot;&gt;Move Function&lt;/a&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice2.png&quot; alt=&quot;Moving rules would be easy if the order of execution of the canonical logic and the indexing logic did not matter&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Moving rules would be easy if the order of execution of the canonical logic and the indexing logic did not matter.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;However, in this case, fixing the shotgun surgery was much more difficult because the order in which the SEO rules had to run was neither in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt; nor in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; but in client code that wasn’t even tested. This meant that there was no way to determine whether moving some logic from one class to the other was preserving the behavior.&lt;/p&gt;

&lt;p&gt;Considering, as already explained, that SEO represented a significant source of revenue for the product, we could not accept the level of risk involved in refactoring without tests that protected all SEO behaviour.&lt;/p&gt;

&lt;p&gt;To reduce the risk of altering the behavior, our strategy was to introduce a new class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt;, whose responsibility was to coordinate the indexing and canonical calculations. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt; explicitly owned the sequence of operations. By centralizing this orchestration logic, we eliminated the implicit, fragile dependencies embedded in the client code.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f84b053b7871d0f9e222500171859a41.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Next, we created a new suite of tests for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt;. This new suite not only included the test cases of both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;, but also new previously missing test cases that protected the order in which the indexing and canonical rules were applied. In this way, we were testing not only each component individually but also the integration between them.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice3.png&quot; alt=&quot;New tests for the new abstraction that encapsulates the order in which indexing and canonical logics are executed&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;New tests for the new abstraction that encapsulates the order in which indexing and canonical logics are executed.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;These tests for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt; gave us enough confidence to start refactoring.&lt;/p&gt;

&lt;p&gt;One rule at a time, we started moving responsibilities to their rightful owners, the indexing logic that had leaked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;, and the canonical logic that had leaked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt; back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;. We deleted tests that were testing logic that was located in the wrong places and used the &lt;a href=&quot;https://refactoring.com/catalog/moveFunction.html&quot;&gt;Move Function&lt;/a&gt; refactoring on the logic.&lt;/p&gt;

&lt;p&gt;Once we finished segregating responsibilities, we removed the redundant tests that were only addressing each separate responsibility (the tests directly against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt;).&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice4.png&quot; alt=&quot;Now we can move the rules with confidence. Once the responsibilities are segregated, we delete the initial tests&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Now we can move the rules with confidence. Once the responsibilities are segregated, we delete the initial tests.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;After applying this refactoring, we achieved the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Cohesive Objects: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexingCalculator&lt;/code&gt; handled only their own responsibilities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Centralized Coordination: The order of execution was neatly encapsulated within &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt;. The calculations remained independent, but their interaction was controlled and tested.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The SEO code adhered to the SRP.&lt;/p&gt;

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

&lt;p&gt;We have presented a real case of &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; and explained how we refactored it to achieve a more cohesive design.&lt;/p&gt;

&lt;p&gt;In simpler situations, addressing &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; might only involve moving logic and tests. But in this context, the untested execution order of the rules, domain complexity, and the high business value of SEO forced us to take a more careful approach. By introducing an intermediate coordinator, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageSEO&lt;/code&gt;, we reduced risk and provided a single place to test and reason about SEO’s behavior.&lt;/p&gt;

&lt;p&gt;If you find yourself in a similar situation, perhaps you can apply some aspects of this solution to reduce risks.&lt;/p&gt;

&lt;p&gt;I hope this explanation was clear and helpful. Feel free to reach out for guidance if you encounter similar challenges or need assistance in improving the design of your project!&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] The reason why the responsibilities became mixed might lie in the design of the interfaces, but this issue may be addressed in a future post.&lt;/p&gt;

</description>
          <pubDate>2025-02-03T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2025/02/a-case-of-shotgun-surgery</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2025/02/a-case-of-shotgun-surgery</guid>
        </item>
      
    
      
        <item>
          <title>An example of wrong port design detection and refinement</title>
          <description>&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h3&gt;

&lt;p&gt;As part of the &lt;strong&gt;Intensive Technical Mentoring Program&lt;/strong&gt; that we recently did for &lt;a href=&quot;https://www.aidacanarias.com/&quot;&gt;AIDA&lt;/a&gt;, we worked on the &lt;a href=&quot;https://www.devjoy.com/blog/legacy-code-katas/&quot;&gt;Legacy Security Manager kata&lt;/a&gt;. This is a great kata to practise &lt;a href=&quot;https://codesai.com/posts/2024/03/mindmup-breaking-dependencies&quot;&gt;dependency-breaking techniques&lt;/a&gt; and how to test and refactor legacy code.&lt;/p&gt;

&lt;h3 id=&quot;2-introducing-tests&quot;&gt;2. Introducing tests.&lt;/h3&gt;

&lt;p&gt;In order to be able to introduce unit tests, we first used the &lt;a href=&quot;https://understandlegacycode.com/blog/quick-way-to-add-tests-when-code-does-side-effects/&quot;&gt;Extract Call &amp;amp; Override&lt;/a&gt; dependency-breaking technique, to create two seams, one to spy what was being written on the console, and another one, to control the user input received through the console.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/37339a3878616edd6a7d42ac7aea892e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Breaking those dependencies allowed us to write the following unit tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7727d9ed56b1b5572a71871b3a8f3dfb.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;3-separating-core-logic-from-infrastructure&quot;&gt;3. Separating core logic from infrastructure.&lt;/h3&gt;

&lt;p&gt;With those tests in place, the pairs started refactoring the code until they were finally able to separate infrastructure from core logic using the “Move Function to Delegate” refactoring&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; to control the awkward dependencies by inverting them and making them explicit. This is the code after the refactoring:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5f4a349554abd78ded57ffa56b8e8994.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the two ports, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notifier&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InputReader&lt;/code&gt;. These ports are the result of directly applying the “Move Function to Delegate” refactoring to the previously existing seams: the methods &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected virtual string Read()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected virtual void Notify(string message)&lt;/code&gt; shown in the previous section.&lt;/p&gt;

&lt;p&gt;This is how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManagerTest&lt;/code&gt; looks after the refactoring:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/cb89c7a77c63978322227a42ad039c35.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;4-some-test-smells-pointing-to-a-design-problem&quot;&gt;4. Some test smells pointing to a design problem.&lt;/h3&gt;

&lt;p&gt;But, if you look closer at the tests, there’s a smell that is pointing to problems in the current design.&lt;/p&gt;

&lt;p&gt;Notice inside the helper method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VerifyNotifiedMessages&lt;/code&gt; how, in order to avoid regressions, we need to enforce the order of the calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notifier&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notify&lt;/code&gt; method so that they coincide with the order in which stubbed values are returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InputReader&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Read&lt;/code&gt; method. If we wouldn’t do this, we might change the code in ways that would break the behaviour but not the tests, thus allowing regressions.&lt;/p&gt;

&lt;p&gt;Having said that, it shouldn’t be necessary to enforce this order concordance between the stubbed calls to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InputReader&lt;/code&gt; and the calls to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notifier&lt;/code&gt;. This is an overspecification that makes the tests more fragile, for instance, changing the order of some of the input requests would break the tests, even though the observable behaviour wouldn’t be changed.&lt;/p&gt;

&lt;p&gt;Another signal that something is amiss is the duplication in the verification of the first four calls to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notifier&lt;/code&gt; which we introduced the helper method, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VerifyNotifiedMessages&lt;/code&gt;, to avoid. This duplication is caused by a leak of implementation details because only the last notification is related to the observable output of the system, and thus, is the only one required to verify the behaviour. We should not need to check the other previous four notifications. The helper method, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VerifyNotifiedMessages&lt;/code&gt;, is removing this duplication and hinting that we are only interested in the last notification, which is better than leaving the duplication, but this only addresses the symptom but not the cause.&lt;/p&gt;

&lt;p&gt;The underlying problem that is causing all this accidental complexity in the tests is that the ports are not well designed.&lt;/p&gt;

&lt;h3 id=&quot;5-how-did-we-get-to-this-point&quot;&gt;5. How did we get to this point?&lt;/h3&gt;

&lt;p&gt;When applying  &lt;a href=&quot;https://understandlegacycode.com/blog/quick-way-to-add-tests-when-code-does-side-effects/&quot;&gt;Extract Call &amp;amp; Override&lt;/a&gt; it’s advisable to change the code as little as possible because this technique is applied without tests&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. Sometimes this may produce seams that are not a good abstraction and are too low level, but that’s ok at that stage, because the goal is to introduce tests assuming as few risks as possible.&lt;/p&gt;

&lt;p&gt;The current ports come directly from applying the “Move Function to
Delegate” refactoring to the seams that we used when we broke the dependencies that were stopping us from introducing unit tests. Many times this is just fine, and seams directly become ports, but this is not always the case, like in the current example.&lt;/p&gt;

&lt;p&gt;The current ports are leaking an implementation detail: that we need to call two methods in sequence in order to get the user input.&lt;/p&gt;

&lt;h3 id=&quot;6-fixing-the-design&quot;&gt;6. Fixing the design.&lt;/h3&gt;

&lt;p&gt;If we think about the purpose or the role of each of the messages written to the console, we may see that they fall in two different categories: some are requests to the user to introduce some specific input, and others are straight away notifications. We may also see that calling two methods in sequence to get the user input is an implementation detail, &lt;em&gt;what&lt;/em&gt; the client (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManager&lt;/code&gt;) needs is just &lt;em&gt;getting the user input&lt;/em&gt;, the two calls in sequence is &lt;em&gt;how&lt;/em&gt; we get the user input.&lt;/p&gt;

&lt;p&gt;Thinking in those different roles we may refactor the code (applying a parallel change) to use the following new interfaces for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Input&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Notifier&lt;/code&gt; ports:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/24fe503e9043a2c20c1a4819bd4b2930.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/89bbe763c0656a5bdf4de061280f48b6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This the new code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManager&lt;/code&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; using the new ports:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/31525d7bafb41532ec51d6b5cabc56dd.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And these are the resulting tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d2ed317df8c68bfdef1187a838118f8a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how this improved design has made disappear the two smells that were present in the previous version of the tests:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;We don’t need to coordinate the order of the stubbed values and the order of the corresponding user input requests anymore.&lt;/li&gt;
  &lt;li&gt;We only notify and verify the message that informs about the result of the operation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;7-conclusions&quot;&gt;7. Conclusions.&lt;/h3&gt;

&lt;p&gt;We have seen how badly designed ports may lead to smells in how test doubles get used in the tests, in the example shown in this post, duplication and overspecification of the order of the calls. Such overspecification, in particular, makes the tests more fragile.&lt;/p&gt;

&lt;p&gt;Those badly designed ports came from blindly applying “Move Function to
Delegate” refactoring to every seam directly. In most cases, applying “Move Function to
Delegate” to seams it’s perfectly ok, but sometimes, it might lead to ill designed ports.&lt;/p&gt;

&lt;p&gt;We saw how thinking about the role or purpose of each interaction led us to better designed ports, and how this new improved design just made the problems in the tests disappear.&lt;/p&gt;

&lt;h3 id=&quot;8-acknowledgements&quot;&gt;8. Acknowledgements.&lt;/h3&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt; for revising drafts of this post.&lt;/p&gt;

&lt;p&gt;Also thanks to the participants in the &lt;strong&gt;Intensive Technical Mentoring Program&lt;/strong&gt; that we recently did for &lt;a href=&quot;https://www.aidacanarias.com/&quot;&gt;AIDA&lt;/a&gt; who worked through the whole kata,
and to &lt;a href=&quot;https://www.audiense.com/about-us/the-team&quot;&gt;Audiense’s developers&lt;/a&gt; which also worked on a &lt;a href=&quot;https://github.com/Codesai/practice_program_ts_audiense/tree/main/13-security-manager&quot;&gt;version of the kata that starts with the ill designed ports&lt;/a&gt; to practise their detection from test smells and refactoring using parallel change to fix the design. It was a pleasure to work with all of you.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@steve/&quot;&gt;Steve Johnson&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h3 id=&quot;9-notes&quot;&gt;9. Notes.&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Documented by Nicolas Carlo in his book &lt;a href=&quot;https://understandlegacycode.com/first-aid-kit/&quot;&gt;Legacy Code: First Aid Kit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] In fact, &lt;a href=&quot;https://codesai.com/posts/2024/03/mindmup-breaking-dependencies&quot;&gt;dependency-breaking techniques&lt;/a&gt; are applied in order to be able to introduce tests.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Keep in mind that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManager&lt;/code&gt;s code reflects a snapshot in time while solving the kata. We didn’t want to divert the focus of the post to anything other than the detection of problems in the tests that led to detecting problems in the port interfaces, and how we refined those interfaces. As such &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManager&lt;/code&gt;s design is still a work in progress. There are still many issues that would be worked later in the kata, such as, for instance:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Where should the responsibility of deciding if the user input is valid or not be? Maybe  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserDataRequester&lt;/code&gt; would be a better place.&lt;/li&gt;
  &lt;li&gt;Finding a better place for the password encryption responsibility, which now is located in a static method in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SecurityManager&lt;/code&gt; (being static is a hint that it doesn’t belong there). Not representing the user password with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; would attract that behaviour and, probably, the password length validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those are material for another story…&lt;/p&gt;

</description>
          <pubDate>2024-10-03T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/10/ill-designed-ports</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/10/ill-designed-ports</guid>
        </item>
      
    
      
        <item>
          <title>Atributos de calidad e historias de usuario en Agile Sur</title>
          <description>&lt;p&gt;El 28 de agosto tuve la oportunidad de hablar sobre atributos de calidad e historias de usuario en &lt;a href=&quot;https://www.meetup.com/es-ES/agile-sur/&quot;&gt;Agile Sur&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Los atributos de calidad son una problemática, de la que creemos, se habla poco pero que tiene mucha importancia a la hora de desarrollar software.&lt;/p&gt;

&lt;p&gt;Los atributos de calidad definen cómo de bien un sistema realiza alguna acción y, por tanto, guardan relación con la arquitectura. Las historias de usuario, por otro lado, nos ayudan a comunicar con negocio lo que es necesario hacer.
En esta charla exploramos cómo comunicamos los atributos de calidad.&lt;/p&gt;

&lt;p&gt;A continuación dejo la grabación que también puede encontrarse en nuestra sección de publicaciones (pestaña videos).&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/2wYZvFW1Hf0&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Las slides se pueden encontrar &lt;a href=&quot;https://drive.google.com/file/d/18N8trRvSQOkZzeAco6QjDqS0_att_rxm/view?usp=drive_link&quot;&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para finalizar, me gustaría agradecer a &lt;a href=&quot;https://www.meetup.com/es-ES/agile-sur/&quot;&gt;Agile Sur&lt;/a&gt; y en especial a &lt;a href=&quot;https://www.linkedin.com/in/rafael-sh/&quot;&gt;Rafael Sobrá Hidalgo&lt;/a&gt; su esfuerzo y generosidad para organizarla.&lt;/p&gt;
</description>
          <pubDate>2024-09-30T11:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/09/atributos-historias-de-usuario-en-agile-sur</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/09/atributos-historias-de-usuario-en-agile-sur</guid>
        </item>
      
    
      
        <item>
          <title>Relevant mutants</title>
          <description>&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h3&gt;

&lt;p&gt;Mutation testing gives us information about the fault detection capability of a test suite, whether the assertions that its tests make are good and strong enough to capture regressions.&lt;/p&gt;

&lt;p&gt;The idea behind it is to purposefully inject a regression in a copy of the code, “the mutant”, run the test suite against this mutant and check if the test suite breaks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;If it does, everything is fine, “the mutant is killed”. This means that the test suite protects us from that kind of regression.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If it does not, “the mutant survives”. This means that the tests don’t protect us from that regression happening. We may have found something to improve in the tests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutation_testing.png&quot; alt=&quot;How mutation testing is used.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;How mutation testing is used.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;However, when we apply mutation testing to legacy code, not all surviving mutants are a signal of weaknesses in the test suite. Some of the survivors may be related to the existence of dead code, and others may be indicating code that is unnecessary to produce the expected behaviour, and, as such, could be simplified. That is why we must analyse each of the surviving mutants to decide if it is relevant or not, and only if it is so, write new test cases to kill it.&lt;/p&gt;

&lt;p&gt;Let’s see it with an example.&lt;/p&gt;

&lt;h3 id=&quot;2-analyzing-the-surviving-mutants-in-the-crazy-portfolio-kata&quot;&gt;2. Analyzing the surviving mutants in the Crazy Portfolio kata.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2024/03/crazy-portfolio-kata&quot;&gt;The Crazy Portfolio kata&lt;/a&gt; is a kata to practise working with legacy code that we recently published. This kata is complicated because the code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Portfolio&lt;/code&gt; class, not only has many responsibilities and complex conditional logic, but also, uses dates and time zones, and has side-effects, many boundary conditions between partitions and some implicit invariants&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://github.com/Codesai/practice_program_ts_audiense/tree/main/09-crazy-portfolio_b&quot;&gt;code&lt;/a&gt; used for this example we had already written characterization tests achieving the maximum possible branch coverage, which is not 100% because there is an unreachable branch in the code, and because of the &lt;a href=&quot;https://martinfowler.com/bliki/LegacySeam.html&quot;&gt;seams&lt;/a&gt; we introduced using &lt;a href=&quot;https://www.youtube.com/watch?v=i7NfgsM4VqA&quot;&gt;Extract and Override Call&lt;/a&gt;, which, of course, are not executed in the tests.&lt;/p&gt;

&lt;p&gt;Depending on the refactoring we plan to do, it might not be enough to have high branch coverage to start refactoring with confidence, so we applied mutation testing using &lt;a href=&quot;https://github.com/stryker-mutator/stryker-js&quot;&gt;Stryker&lt;/a&gt; and the results were that 36 out of 160 mutants survived.&lt;/p&gt;

&lt;p&gt;Apparently, we would need to kill a lot of mutants by adding new test cases in order to improve our test suite, and perhaps some of the mutants might not be so easy to kill.&lt;/p&gt;

&lt;p&gt;If we analyse the surviving mutants, we’ll see that there really aren’t that many mutants to kill.&lt;/p&gt;

&lt;p&gt;The surviving mutants fall into the following categories:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Mutants in dead code.&lt;/li&gt;
  &lt;li&gt;Mutants in seams.&lt;/li&gt;
  &lt;li&gt;Mutants in code not used in the tests because of the seams.&lt;/li&gt;
  &lt;li&gt;Mutants in superfluous code that don’t point to weaknesses in the test suite.&lt;/li&gt;
  &lt;li&gt;Mutants that do point to weaknesses in the test suite.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;2-1-mutants-in-dead-code&quot;&gt;2. 1. Mutants in dead code.&lt;/h4&gt;

&lt;p&gt;This category includes all the mutations in the non-accessible branch in line 60 that we identified when we wrote the characterization tests.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irelevant_mutants_in_dead_code.png&quot; alt=&quot;Surviving mutations in dead code are irrelevant.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutations in dead code are irrelevant.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;These surviving mutants are obviously irrelevant.&lt;/p&gt;

&lt;h4 id=&quot;2-2-mutants-in-seams&quot;&gt;2. 2. Mutants in seams.&lt;/h4&gt;

&lt;p&gt;All the mutants in the seams that we introduced, as for instance, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createDate&lt;/code&gt; method seen in the following fragment of the Stryker report, are not relevant because the seams’ code is not executed in the tests.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irrelevant_mutants_in_seams.png&quot; alt=&quot;Surviving mutations in seams are irrelevant.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutations in seams are irrelevant.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The same happens for the mutants inside the other seams, the protected methods: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;formatDate&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAssetLines&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;displayMessage&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getNow&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;2-3-mutants-in-code-not-used-in-the-tests-because-of-the-seams&quot;&gt;2. 3. Mutants in code not used in the tests because of the seams.&lt;/h4&gt;

&lt;p&gt;In this group we find the mutation that survives in the constructor of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Portfolio&lt;/code&gt; class,&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/irrelevant_mutants_in_unused_code_due_to_seams.png&quot; alt=&quot;Surviving mutations in unused code due to seams are irrelevant.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutations in unused code due to seams are irrelevant.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Since we introduced a seam to get the assets without actually reading the file in the unit tests, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;portfolioCsvPath&lt;/code&gt; field is not used. Therefore this mutant survival is related to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAssetLines&lt;/code&gt; seam that we introduced, and this means that it is not a relevant mutant.&lt;/p&gt;

&lt;h5 id=&quot;about-the-categories-we-have-seen-so-far&quot;&gt;About the categories we have seen so far.&lt;/h5&gt;

&lt;p&gt;The surviving mutants in the three categories we’ve seen so far can be quickly and safely ignored because they don’t provide any hints on how to improve the test suite or the production code.&lt;/p&gt;

&lt;p&gt;We’ll need to examine one by one the rest of the surviving mutants to see if they actually point to weaknesses in our tests or production code that may be simplified. Let’s see the two remaining categories.&lt;/p&gt;

&lt;h4 id=&quot;2-4-mutants-in-superfluous-code-that-dont-point-to-weaknesses-in-the-test-suite&quot;&gt;2. 4. Mutants in superfluous code that don’t point to weaknesses in the test suite.&lt;/h4&gt;

&lt;p&gt;Let’s look at the most interesting examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Case 1: Mutations surviving in line 29.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have a look at:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_changing_division_in_before_or_after_boolean_expression_1.png&quot; alt=&quot;Surviving mutation changing / operator to * operator in line 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation changing / operator to * operator in line 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;or at:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_changing_division_in_before_or_after_boolean_expression_2.png&quot; alt=&quot;Another surviving mutation changing * operator to / operator in line 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Another surviving mutation changing * operator to / operator in line 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There are several more similar mutations on the same line.&lt;/p&gt;

&lt;p&gt;These mutations that replace the division operator with the product operator, and viceversa, seem very confusing and may, at first, be baffling. Why do they survive?&lt;/p&gt;

&lt;p&gt;To understand it, we need to look closer at the condition and what it means. The only relevant thing to make the condition true or false is the sign of the difference of the two times in milliseconds: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset.getDate().getTime() - now.getTime()&lt;/code&gt;. The rest of the expression, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1000 * 60 * 60 * 24)&lt;/code&gt;, is just a positive number that is dividing the previously mentioned difference, but it will not change its sign, and therefore, it will not change the evaluation of the boolean expression &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.floor(difference / positive_number) &amp;lt; 0&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;These mutants, that change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; operators to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; operators, and viceversa, therefore, are not pointing to weaknesses in our tests. What they are indicating, instead, is production code that we don’t need, and, which we could simplify&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;, writing the following condition instead: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.floor(asset.getDate().getTime() - now.getTime()) &amp;lt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This simplification (that we’d do only once we have stronger tests that eliminate all the relevant mutants) would be enough to eliminate all the related mutants.&lt;/p&gt;

&lt;p&gt;The only surviving mutant in line 29 that is relevant to improve our tests is the one that changes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; operator to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt; operator.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_before_or_after_boolean_expression.png&quot; alt=&quot;Surviving mutation changing &amp;lt; operator to &amp;lt;= operator in line 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation changing &amp;lt; operator to &amp;lt;= operator in line 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This surviving mutant indicates that our tests are not correctly exercising a boundary condition that exists between two partitions of the values that the difference between the date of the assets and the date the portfolio value is being calculated can take.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Case 2. Mutations surviving in line 27.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_in_mapping_to_value_objects.png&quot; alt=&quot;Surviving mutation when mapping to value object in line 27.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation when mapping to value object in line 27.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The survival of those mutations means that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PricelessValue&lt;/code&gt; class is not necessary to achieve the behaviour that the tests are protecting. How do they survive?&lt;/p&gt;

&lt;p&gt;These mutations survive because the derived &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PricelessValue&lt;/code&gt; class is not used at all in the code. The only thing that is used is the getter of the base object of the hierarchy, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MeasurableValue&lt;/code&gt;, and therefore the entire inheritance hierarchy is superfluous. The root cause of this problem is the &lt;a href=&quot;https://wiki.c2.com/?FeatureEnvySmell&quot;&gt;feature envy&lt;/a&gt; against the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Asset&lt;/code&gt; class present in the current code.&lt;/p&gt;

&lt;p&gt;Again these mutants are not relevant to improve our tests and we do not have to waste time trying to kill them.&lt;/p&gt;

&lt;p&gt;Once we have stronger tests that eliminate all the relevant mutants, we can refactor the code to eliminate the rampant feature envy, and decide if we need to keep the hierarchy or not. These mutants would disappear then.&lt;/p&gt;

&lt;h4 id=&quot;5-mutants-that-do-point-to-weaknesses-in-the-test-suite&quot;&gt;5. Mutants that do point to weaknesses in the test suite.&lt;/h4&gt;
&lt;p&gt;We’ve already seen an example in line 29 of a mutant that was indicating that our tests are not correctly exercising a boundary condition. This surviving mutant is changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; operator to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_before_or_after_boolean_expression.png&quot; alt=&quot;Surviving mutation changing &amp;lt; operator to &amp;lt;= operator in line 29.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation changing &amp;lt; operator to &amp;lt;= operator in line 29.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There are other surviving mutants similar to the previous one that also indicate problems testing boundary values, for instance the ones in the lines 32 and 46 presented below:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_value_lower_boundary.png&quot; alt=&quot;Surviving mutation in line 32 related to problems testing boundary values.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation in line 32 related to problems testing boundary values.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/relevant_mutant_in_value_upper_boundary.png&quot; alt=&quot;Surviving mutation in line 46 related to problems testing boundary values.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation in line 46 related to problems testing boundary values.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Another example of a surviving mutant that may point to a weakness in our test suite is the one in line 22 showed below:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/mutant_in_exception_message.png&quot; alt=&quot;Surviving mutation in line 22 related to not checking an exception message.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Surviving mutation in line 22 related to not checking an exception message.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If we examine the test suite, we’ll see that we are testing that an error is thrown when the date is badly formatted, but we are not checking the error message. In this case, depending on if we want the tests to be coupled with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;”wrong date”&lt;/code&gt; string or not, we may decide to kill this mutant or not. We decided to ignore this mutant to avoid coupling the tests to the exception message.&lt;/p&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h3&gt;

&lt;p&gt;We’ve shown an example of how not all surviving mutants point to weaknesses in our test suites. Of the original 36 surviving mutants, only 13 of them were relevant to improve our tests suite&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; (we chose to ignore the one related to the error message). Those 13 mutants are related to boundary conditions that are not being properly exercised by the test suite.&lt;/p&gt;

&lt;p&gt;Having to kill 13 mutants is a much less daunting task than killing 36 of them. A nice thing is that most of the discarded, not relevant mutants were easy to identify: the ones related to the existence of dead code&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; and to the introduction of seams. This is great because, sometimes, surviving mutants might not be so easy to kill&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We also saw another category of surviving mutants that, even though, do not point to improvements in the test suite, are a signal of code that may be unnecessary to achieve the desired behaviour. We may decide to take advantage of these hints in later refactorings once the test suite has improved by killing the relevant mutants.&lt;/p&gt;

&lt;p&gt;I hope this detailed example may prove useful to you when you analyse mutation testing results.&lt;/p&gt;

&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h3&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/rub%C3%A9n-d%C3%ADaz-mart%C3%ADnez-b9276395/&quot;&gt;Rubén Díaz&lt;/a&gt; for revising drafts of this post.&lt;/p&gt;

&lt;p&gt;Also thanks to &lt;a href=&quot;https://www.audiense.com/about-us/the-team&quot;&gt;Audiense’s developers&lt;/a&gt; for being the beta testers of the &lt;a href=&quot;https://codesai.com/posts/2024/03/crazy-portfolio-kata&quot;&gt;Crazy Portfolio kata&lt;/a&gt; as part of our &lt;strong&gt;deliberated practice sessions&lt;/strong&gt;. It is always a pleasure to work with you.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@cgoulao/&quot;&gt;Carlos Machado&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes.&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] We use a simplified version of this kata in our &lt;a href=&quot;https://codesai.com/cursos/changing-legacy/&quot;&gt;Changing Legacy Code training&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] We already talked about surviving mutants pointing to redundant code in a previous post: &lt;a href=&quot;https://codesai.com/posts/2022/02/mutation-testing&quot;&gt;Mutando para simplificar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] The 13 relevant surviving mutations are in lines 29 (1), 32 (2), 46 (2), 70 (1), 71 (2), 76 (1), 77 (2) and 83 (2).&lt;/p&gt;

&lt;p&gt;The surviving mutations in lines 32, 46, 77, and 83 point to boundary conditions which are completely ignored by the test suite (that’s why one of the surviving mutations can completely remove the condition), whereas the surviving mutations in lines 29, 70 and 76 point to partially tested boundary conditions.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] We advise using a coverage tool to detect uncovered and dead code before running a mutation testing tool, because coverage tools results are easier to analyze than the mutation testing tools’ ones.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Testing boundary conditions, and, hence, killing mutants related to them becomes much easier if you know about boundaries’ on and off points. These knowledge provides you a systematic way if killing this kind of mutants. We teach these concepts in our revamped &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;TDD training&lt;/a&gt; material.&lt;/p&gt;

</description>
          <pubDate>2024-07-22T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/07/relevant-mutants</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/07/relevant-mutants</guid>
        </item>
      
    
      
        <item>
          <title>&quot;Move seam to delegate&quot; refactoring</title>
          <description>&lt;p&gt;We’d like to document a refactoring that we usually teach to teams we work with: the &lt;em&gt;Move seam to delegate&lt;/em&gt; refactoring.&lt;/p&gt;

&lt;h2&gt;Move seam to delegate.&lt;/h2&gt;

&lt;h3 id=&quot;motivation&quot;&gt;Motivation.&lt;/h3&gt;

&lt;p&gt;Sometimes we want to move some code to a delegate but that code contains a protected 
method we’re overriding in our tests in order to sense or 
separate&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. That method is an object &lt;a href=&quot;https://martinfowler.com/bliki/LegacySeam.html&quot;&gt;seam&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/move-seam-to-delegate-initial.png&quot; alt=&quot;The tests (the violet eye) are coupled to the seam.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;The tests (the violet eye) are coupled to the seam.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Our current tests are anchoring that method because if we move it, all the tests will fail.&lt;/p&gt;

&lt;p&gt;Let’s see an example.&lt;/p&gt;

&lt;p&gt;Have a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ffe46975c7634260c2ba440f2115a72a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We’d like to move the logic that sends greetings by email to a different class in order to decouple the infrastructure logic from the domain logic.&lt;/p&gt;

&lt;p&gt;The problem is that we can’t move the protected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method because, if we do it all the tests would fail.&lt;/p&gt;

&lt;p&gt;This method was introduced by applying the &lt;em&gt;Extract &amp;amp; Override Call&lt;/em&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; dependency-breaking technique in order to test &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt;, and it’s being overridden in our tests.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7508d8d52e28c6c4c4709310b99c7b0b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;That seam allowed us to spy which emails were going to be sent, and to avoid the undesired side-effect of actually sending emails every time we run the tests.&lt;/p&gt;

&lt;p&gt;If we want our tests to allow us moving the logic that sends the email to a different class, we’ll first need to &lt;em&gt;move the seam&lt;/em&gt; to that class. Let’s see how we can perform this &lt;em&gt;Move seam to delegate&lt;/em&gt; refactoring safely.&lt;/p&gt;
&lt;h3 id=&quot;mechanics&quot;&gt;Mechanics.&lt;/h3&gt;

&lt;p&gt;We’ll do a &lt;a href=&quot;https://martinfowler.com/bliki/ParallelChange.html&quot;&gt;parallel change&lt;/a&gt; of the tests in order to move the seam to the delegate where we’d eventually like to move the code. These are the steps to do it:&lt;/p&gt;

&lt;h4 id=&quot;1-expand&quot;&gt;1. Expand.&lt;/h4&gt;
&lt;p&gt;a. Create the delegate class if it doesn’t exist yet, and initialise a field with its type in the constructor of the class being tested. 
Use &lt;em&gt;Parameterize Constructor&lt;/em&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; to inject the delegate in the class.&lt;/p&gt;

&lt;p&gt;b. Copy the overridden method in the delegate and make it public&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;c. &lt;em&gt;Subclass &amp;amp; Override&lt;/em&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; the delegate class in the tests, and do in its overridden method exactly what the class under test overridden method was doing (stubbing or spying).&lt;/p&gt;

&lt;p&gt;d. Inject an instance of the delegate’s subclass in the class under test.&lt;/p&gt;

&lt;p&gt;Let’s see how the code of our example looks at the end of the &lt;em&gt;expand phase&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;a. This is the code of the delegate we created, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailGreetingsSender&lt;/code&gt;, where we copied the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1dc4633f48d2f2d30d18df76f525f504.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;b. This is the change we did in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt;, by introducing an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailGreetingsSender&lt;/code&gt; field, initialising it in the constructor and applying &lt;em&gt;Parameterize Constructor&lt;/em&gt; in this case using the &lt;em&gt;Introduce Parameter&lt;/em&gt; refactoring which was  automated by the IDE we were using&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/adea14ba10f916896aed19a76a2ecbf8.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;c. Finally this is the change in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setUp&lt;/code&gt; method of the tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt;. Notice how we are applying &lt;em&gt;Subclass &amp;amp; Override&lt;/em&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailGreetingsSender&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method, and how both seams do exactly the same:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/be51ae585800cc572b8eb49d71dc8bf6.js&quot;&gt;&lt;/script&gt;

&lt;h4 id=&quot;2-migrate&quot;&gt;2. Migrate.&lt;/h4&gt;

&lt;p&gt;Change the production code so that it calls the public method in the delegate instead of the originally overridden protected method. The tests should keep passing.&lt;/p&gt;

&lt;p&gt;In our example, the migration phase involves just changing the place in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt; where the protected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method is called,
So that it calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailGreetingsSender&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage(msg);&lt;/code&gt; changes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;greetingsSender.sendMessage(msg);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;All the tests should keep passing after doing that change.&lt;/p&gt;

&lt;h4 id=&quot;3-contract&quot;&gt;3. Contract.&lt;/h4&gt;

&lt;p&gt;In this phase we delete all the resulting dead code.&lt;/p&gt;

&lt;p&gt;First, we delete the dead code in the tests: the method that was overriding the seam, and, if possible, also the subclass of the class under test used for testing purposes. 
After doing these the tests should still pass.&lt;/p&gt;

&lt;p&gt;Finally, we also remove the dead code in production: the overridden protected method that originally provided the seam.&lt;/p&gt;

&lt;p&gt;In our example, we first delete the anonymous class that was overriding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt; for testing purposes, which it’s not needed anymore.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/267319464ed4485982b9eeee78419f0c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And then, delete the protected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; method in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BirthdayGreetingsService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After applying this parallel change to the tests, the seam is now located in the delegate, and
we can freely move the code that uses the seam.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/move-seam-to-delegate-final.png&quot; alt=&quot;Now the tests (the violet eye) are coupled to the seam in the delegate and we can freely move there the logic that sends greetings by email.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Now the tests (the violet eye) are coupled to the seam in the delegate and we can freely move there the logic that sends greetings by email.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion.&lt;/h3&gt;
&lt;p&gt;We have described the &lt;em&gt;Move seam to delegate&lt;/em&gt; refactoring mechanics. We hope this refactoring technique might be useful to you when working with seams in legacy code.&lt;/p&gt;

&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h3&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for revising and giving feedback about this blog post.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@enginakyurt/&quot;&gt;Engin Akyurt&lt;/a&gt; for the photo.&lt;/p&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;
&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Generally, when we break dependencies to get tests in place, we do it for either sensing or separating:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Sensing is about being able to know values that our code computes, but we can’t access.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Separating is about avoiding side-effects that don’t even let us run a piece of code in a test harness.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The seam in the example we use throughout the post is used to sense the emails sent by the code.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] &lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt; describes the &lt;em&gt;Extract &amp;amp; Override Call&lt;/em&gt; dependency-breaking technique in chapter 25 of  his book, &lt;a href=&quot;https://www.goodreads.com/en/book/show/44919&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt;. It’s a variation of the &lt;em&gt;Subclass &amp;amp; Override&lt;/em&gt; dependency-breaking technique&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] &lt;em&gt;Parameterize Constructor&lt;/em&gt; is another dependency-breaking technique described in &lt;a href=&quot;https://www.goodreads.com/en/book/show/44919&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt;, in which you safely add a new parameter to a constructor in order to introduce an object seam.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] If the protected method has some dependencies on other fields or methods of the class, you’d need to do more work. However, these dependencies on the class are likely a sign that the extraction to create the seam was too coarse-grained. A finer-grained seam with just the code that calls the awkward dependency and that receives any required class data as parameters would be much safer.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] &lt;em&gt;Subclass &amp;amp; Override&lt;/em&gt; is another dependency-breaking technique described in &lt;a href=&quot;https://www.goodreads.com/en/book/show/44919&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt;, in which we use inheritance to override the behaviour of a method (our seam) in order to sense or separate, without affecting the behaviour we’d like to test. In the example we use throughout the post, we used it to sense the emails sent by the delegate.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] You can find an explanation of how to apply this automated refactoring with IntelliJ Idea in this &lt;a href=&quot;https://www.youtube.com/watch?v=c5DrkPSmu9o&quot;&gt;video&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2024-05-09T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/05/move-seam-to-delegate</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/05/move-seam-to-delegate</guid>
        </item>
      
    
      
        <item>
          <title>Experiencia en el AOS Tenerife 2024</title>
          <description>&lt;p&gt;El 4 y 5 de mayo algunos de mis compañeros y yo estuvimos en Agile Open Space que tuvo su edición en Tenerife. 
La experiencia del evento fue fantástica ya que la organización puso todo su empeño para que fuera todo un éxito. 
Las propuestas, el espacio, la comida y las sorpresas fueron un acierto.&lt;/p&gt;

&lt;p&gt;Los que fuimos de Codesai estuvimos activos participando, proponiendo charlas y debates.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2024-05-07-aos-tenerife/aos-codesai.jpeg&quot; alt=&quot;Codesai en el AOS de Tenerife 2024&quot; /&gt;
&lt;/figure&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2024-05-07-aos-tenerife/aos-propuestas.png&quot; alt=&quot;Propuestas de Codesai en el AOS de Tenerife 2024&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Mi compañero &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Toño de la Torre&lt;/a&gt; propuso una charla “polémica” a la que llamó “Agile se ha disuelto ¿Qué quedó de Agile?” que tuvo bastante acogida y en la que hubo debates y puntos de vista diferentes y enriquecedores.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7192607107064414210&quot;&gt;
&lt;img src=&quot;/assets/posts/2024-05-07-aos-tenerife/linkedin1.png&quot; alt=&quot;Charla propuesta por Toño en el AOS de Tenerife 2024&quot; /&gt;
&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;Yo me animé a hacer tres propuestas. La primera fue “¿Qué historias te cuentan?” en la que quería que hablásemos sobre las historias de usuario y si estás eran más escritas que contadas. 
Ya hace tiempo que percibimos que la conversación es la gran ausente en las historias de usuario, lo cuál atenta contra su propia esencia. 
Además también hablamos de heurísticas que nos pueden ayudar a que las historias de usuario no se nos atraganten.&lt;/p&gt;

&lt;p&gt;La segunda fue “El Legacy que nos acecha” en la que intenté iniciar un debate sobre cómo nos enfrentamos con ese gran reto desde tres aspectos: la aptitud, las técnicas y la estrategia. 
Los asistentes estuvieron muy colaborativos aportando diferentes puntos de vista sobre lo que es Legacy, modos de atacar el legacy y diferentes experiencias con el mismo.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7192483594919960576/&quot;&gt;
&lt;img src=&quot;/assets/posts/2024-05-07-aos-tenerife/linkedin2.png&quot; alt=&quot;Charla propuesta por Fran en el AOS de Tenerife 2024&quot; /&gt;
&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;En la tercera y última titulada “Cómo las prácticas técnicas nos ayudan a eliminar waste” exploramos cómo diferentes prácticas técnicas nos ayudan a evitar los siete tipos de waste descritos  en &lt;a href=&quot;https://www.goodreads.com/book/show/349417.Implementing_Lean_Software_Development&quot;&gt;Implementing Lean Software Development&lt;/a&gt;. 
Este ejercicio es una parte de una introducción a Lean que hemos dado en la primera edición del Programa de Mentoring Intensivo en Prácticas Técnicas que estamos haciendo con &lt;a href=&quot;https://www.aidacanarias.com/&quot;&gt;AIDA&lt;/a&gt;. 
Para guiar y explicar algunos aspectos partí de estas &lt;a href=&quot;https://drive.google.com/file/d/1gw0xgrM_P5TK_ySHY3gJeygttMwMV9Pl/view?usp=sharing&quot; target=&quot;_blank&quot;&gt;slides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finalmente me gustaría agradecer a todos los asistentes al AOS Tenerife su participación y especialmente a la organización por todo su esfuerzo y generosidad.&lt;/p&gt;

&lt;p&gt;Si quieres saber como fue en el AOS de Tenerife sigue el hashtag en &lt;a href=&quot;https://twitter.com/hashtag/aos24tenerife?src=hashtag_click&quot;&gt;twitter&lt;/a&gt; o en &lt;a href=&quot;https://www.linkedin.com/feed/hashtag/?keywords=aos24tenerife&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2024-05-07T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/05/aos-tenerife</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/05/aos-tenerife</guid>
        </item>
      
    
      
        <item>
          <title>Classifying dependency-breaking techniques</title>
          <description>&lt;p&gt;In his book &lt;a href=&quot;https://www.goodreads.com/en/book/show/44919&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt;, 
&lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt; describes 24 dependency-breaking techniques. 
They are listed in chapter 25.&lt;/p&gt;

&lt;p&gt;We are using the following classification of dependency-breaking techniques:&lt;/p&gt;

&lt;figure&gt;
&lt;a href=&quot;https://github.com/Codesai/website/blob/main/assets/categorized-dependency-breaking-techniques-with-legend-bigger.png&quot;&gt;
&lt;img src=&quot;/assets/categorized-dependency-breaking-techniques-with-legend-bigger.png&quot; alt=&quot;Classification of dependency-breaking techniques&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;/a&gt;
&lt;figcaption&gt;&lt;strong&gt;Classification of dependency-breaking techniques.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We think that this classification may create meaningful chunks of information
that will help us learn, understand and remember these dependency-breaking techniques better. 
These chunks give more cohesion to the material than the list.&lt;/p&gt;

&lt;p&gt;We created this classification, after reading the descriptions of the techniques, 
and thinking about how we could teach them. We think that some techniques are more related to each other than to other techniques, 
but those relationships were not explicitly expressed in the structure of chapter 25 of the book. 
Moreover, some techniques are useful only for some languages.&lt;/p&gt;

&lt;p&gt;This classification is part of a legacy code training that we are launching next month.&lt;/p&gt;

&lt;p&gt;Would you classify the dependency-breaking techniques in a different way? 
Any feedback and suggestions about this classification would be more than welcome.&lt;/p&gt;

&lt;p&gt;I hope this might be useful for you.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for preparing this legacy code training with me.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@vinur-454804393/&quot;&gt;Vinur&lt;/a&gt; for the photo.&lt;/p&gt;
</description>
          <pubDate>2024-03-27T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/03/mindmup-breaking-dependencies</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/03/mindmup-breaking-dependencies</guid>
        </item>
      
    
      
        <item>
          <title>The Crazy Portfolio kata, a short kata to practice breaking dependencies, testing and refactoring legacy code</title>
          <description>&lt;p&gt;We created this short legacy code kata to practice dependency breaking, testing and refactoring techniques. 
It’s called the Crazy Portfolio kata.&lt;/p&gt;

&lt;p&gt;It is part of a legacy code course that we are launching next month. 
We’re currently working on this kata on the deliberate practice sessions we are doing with &lt;a href=&quot;https://es.audiense.com/&quot;&gt;Audiense&lt;/a&gt;’s developers.&lt;/p&gt;

&lt;p&gt;The kata has many things to make legacy-code lovers happy: side effects, nasty nested conditionals, no documentation,
lots of duplication, dead code and interesting boundary conditions.&lt;/p&gt;

&lt;p&gt;This is the TypeScript’s code to whet your appetite:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5f8b63edfe7f0b66c16386c9c2b08e65.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The Crazy Portfolio Legacy kata can be used to practice techniques, such as, dependency breaking, characterization testing, 
structural testing, approval testing, mutation testing and, of course, refactoring.&lt;/p&gt;

&lt;p&gt;You can find the whole code in this repository: &lt;a href=&quot;https://github.com/trikitrok/crazy-portfolio-kata/tree/main&quot;&gt;Crazy Portfolio kata&lt;/a&gt;.
Soon, we’ll add versions for other languages. Pull requests are more than welcome.&lt;/p&gt;

&lt;p&gt;I hope you enjoy solving it.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; for facilitating this kata with me.&lt;/p&gt;

&lt;p&gt;Also thanks to &lt;a href=&quot;https://es.audiense.com/&quot;&gt;Audiense&lt;/a&gt;’s developers for being the beta testers of this kata. 
It is always a pleasure to work with you.&lt;/p&gt;

&lt;p&gt;Finally, I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@josue-miranda-593117802/&quot;&gt;Josue Miranda&lt;/a&gt; for the photo.&lt;/p&gt;
</description>
          <pubDate>2024-03-21T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/03/crazy-portfolio-kata</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/03/crazy-portfolio-kata</guid>
        </item>
      
    
      
        <item>
          <title>Using code smells to refactor to more OO code (an example with temporary field, solution sprawl and feature envy)</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;During our deliberate practice program&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;, we were working on a modified version of 
the &lt;a href=&quot;https://simcap.github.io/coffeemachine/&quot;&gt;CoffeeMachine kata&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. After some sessions we had implemented the following 
functionality documented by the tests:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/temporary_field_post_tests_for_initial_code1.png&quot; alt=&quot;Tests describing the behaviour of the coffee machine.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Tests describing the behaviour of the coffee machine.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;which was implemented by the following code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt; class: 
&lt;script src=&quot;https://gist.github.com/trikitrok/02c7e1780a974601b06731397cca3123.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class: 
&lt;script src=&quot;https://gist.github.com/trikitrok/d31441eb7805f23b4402ce2daa3af6ec.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Most of the logic to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; that is later passed to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DrinkMakerDriver&lt;/code&gt; has been moved to the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class. This class originally started as an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderBuilder&lt;/code&gt; (see &lt;a href=&quot;https://en.wikipedia.org/wiki/Builder_pattern&quot;&gt;Builder design pattern&lt;/a&gt;) with the 
idea that it would gradually build an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; as the user selected how they wanted their drink to be. At some point, we 
decided not to use the name of the pattern to name the class, and we came up with the idea of calling it 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;, although, in essence, it was still a builder.&lt;/p&gt;

&lt;p&gt;One thing that didn’t fit, though, was that there was a case of &lt;a href=&quot;https://luzkan.github.io/smells/temporary-field&quot;&gt;Temporary Field code smell&lt;/a&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;: 
the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectedDrink&lt;/code&gt; field was not being set on the constructor of the class and it remained undefined until 
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectDrink&lt;/code&gt; was called. Moreover, the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectedDrink&lt;/code&gt; field is used to control the flow of the 
processing of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; because an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; can’t be placed until a drink has been selected (if the user tried to make 
a drink before selecting it, the user was notified that it was not possible and a drink should be selected first). 
Besides, not all drinks can be extra hot. There was no clear way to remove this Temporary Field.&lt;/p&gt;

&lt;p&gt;A Temporary Field code smell is usually telling us that there might be a missing abstraction, but knowing which one is 
not so easy. In this case, there were two separate stages in the processing, one before selecting a drink and another 
one after selecting the drink. Those two stages of the order processing might be modelled using the following state machine:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/order_processing_initial_state_machine.png&quot; alt=&quot;State machine for the processing of an order.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;State machine for the processing of an order.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;See how the transition between the first state and the second one is caused by the first time a drink is selected, 
and the transition from the second state to the first one is caused by making a drink.&lt;/p&gt;

&lt;p&gt;In the code part of the order processing logic was leaking into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; method
of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt; class instead of being instead of being wholly contained in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9f99768dddea04db0b664d5a77eccea7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how we had to add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isOrderReady&lt;/code&gt; predicate to ask &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; if an order is ready to be placed. 
This predicate was required to alleviate the missing abstractions representing the two phases of the order processing 
we mentioned before. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; was also using other two methods of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isThereEnoughMoney&lt;/code&gt; predicate
to ask if there’s enough money to pay for the order, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createOrder&lt;/code&gt; method of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; to create an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; object. 
So, there was a &lt;a href=&quot;https://luzkan.github.io/smells/feature-envy&quot;&gt;Feature Envy code smell&lt;/a&gt; because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; method manipulated more features of the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class than from its own.&lt;/p&gt;

&lt;p&gt;Besides, since the responsibility of making a drink was sprawled across the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; classes, 
there was a Solution Sprawl code smell&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;, even though it was an interesting abstraction, was not well designed.&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; was not an honest name yet.&lt;/p&gt;

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

&lt;h3 id=&quot;tell-dont-ask&quot;&gt;Tell don’t ask.&lt;/h3&gt;

&lt;p&gt;We wanted to refactor our original code to an explicit state machine using the &lt;a href=&quot;https://en.wikipedia.org/wiki/State_pattern&quot;&gt;state design pattern&lt;/a&gt;. 
The problem to do that was to find a common interface for both states.&lt;/p&gt;

&lt;p&gt;The interface of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; was in the way. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; had some methods following a typical builder’s interface 
(some methods that incrementally configure the object that we want to create plus a method that returns the built object) 
and the two predicates that we mentioned before, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isOrderReady&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isThereEnoughMoney&lt;/code&gt;, that were needed because 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createOrder&lt;/code&gt; could not be called without having previously selected a drink and having enough money.&lt;/p&gt;

&lt;p&gt;A possible option that could have been considered was to continue insisting on the idea of a builder and return different 
types depending on the moment in which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createOrder&lt;/code&gt; was being called. Those types would have represented 
either a valid order, or an invalid order due to different reasons (not selected drink or not enough money). 
There are different ways to implement this option, but all of them except using some kind of polymorphism on the 
returning type would complicate the client of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt;, with checks on the returned type 
that would result in a &lt;a href=&quot;https://luzkan.github.io/smells/special-case&quot;&gt;Special Case code smell&lt;/a&gt; and thus a violation of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution principle&lt;/a&gt;. 
A solution using polymorphism on the returning type would avoid the Special Case code smell, but will continue to 
suffer from the Solution Sprawl code smell because the processing of an order would be sprawled among several classes.&lt;/p&gt;

&lt;p&gt;In order to get to a better solution, we needed to first fix the Feature Envy code smell in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; method of 
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt; class. Once responsibilities were assigned to the right objects, the other code smells would become 
easier to fix.&lt;/p&gt;

&lt;p&gt;If you think about the style of the code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; is an “ask” style in which we’re pulling all the information to one 
place in order to decide what to do. A better way of structuring this code would be to follow a 
&lt;a href=&quot;https://martinfowler.com/bliki/TellDontAsk.html&quot;&gt;“Tell don’t ask” style&lt;/a&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. So we moved the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; method to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class. 
Notice how to do that we had to pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DrinkMakerDriver&lt;/code&gt; collaborator as a parameter to the new method. We also renamed the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeDrink&lt;/code&gt; method to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;placeOrder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the code of the&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeMachine&lt;/code&gt; class after this refactoring:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/276acb221f78ba22bcf222ca63a4d442.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/576eeda9ea1e459361f2340ac2e10c40.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We think that the resulting code after this refactoring has several benefits:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;It concentrates all the responsibility of processing an order in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class which removes the Solution Sprawl code smell.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We removed all the predicate methods that were asking about the state of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; objects from its interface. 
Those methods are now private in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; instead of public. No more Feature Envy code smell.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The creation of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; is now a private detail of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; instead of part of its public interface.
We think this makes sense because creating an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; object is just a part of processing an order.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; has an interface that makes sense for all the stages of the order processing. Notice how we made 
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;placeOrder&lt;/code&gt; method return an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; object. This allows &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;placeOrder&lt;/code&gt; to reset the order processing.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;introducing-missing-abstractions-to-get-to-the-state-design-pattern&quot;&gt;Introducing missing abstractions to get to the State design pattern.&lt;/h3&gt;

&lt;p&gt;This new design following the “Tell don’t ask” style enabled us to refactor to the State design pattern. 
To do it we introduced two classes that represented the two states of processing an order, and had the same 
interface that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InitialOrderProcessing&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToPlaceOrderProcessing&lt;/code&gt;. See the state diagram below:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/order_processing_state_machine.png&quot; alt=&quot;State machine for the processing of an order.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;State machine for the processing of an order.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is the code of the two new classes:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c9471f1e488c613fd68080de3ffe4eaf.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d72f685c7bbc91e3c49915614993fe1f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The temporary field code smell was removed because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectedDrink&lt;/code&gt; field does not exist in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InitialOrderProcessing&lt;/code&gt;. 
Now the field only appears in the other variant of ‘&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToPlaceOrderProcessing&lt;/code&gt;, and it’s assigned 
a value in the constructor of the class.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Each state of the order processing has its own behaviour and only the required private methods are included in each class. 
This resulted in more cohesive classes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isOrderReady&lt;/code&gt; method disappeared because the need for this check was not necessary any more. Passing to polymorphism eliminated it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The transition from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InitialOrderProcessing&lt;/code&gt; state to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToPlaceOrderProcessing&lt;/code&gt; state is provoked by calling 
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selectDrink&lt;/code&gt; method on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InitialOrderProcessing&lt;/code&gt;, and the transition from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToPlaceOrderProcessing&lt;/code&gt; to 
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InitialOrderProcessing&lt;/code&gt; state is provoked by calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;placeOrder&lt;/code&gt; method on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadyToPlaceOrderProcessing&lt;/code&gt;, 
as indicated in the state machine diagram.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, this is the code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; class which became an abstract class that contained only the code for 
the setters shared by the two variants of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt;. Notice how we made abstract the non shared setters and the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;placeOrder&lt;/code&gt; method. We also used protected accessors to encapsulate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; state and avoid the 
&lt;a href=&quot;https://wiki.c2.com/?InappropriateIntimacy&quot;&gt;Inappropriate Intimacy code smell&lt;/a&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2777b9d23918804fe1e30f8429219d7e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;All three classes are contained in the same module and only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; is exported, so that its different states 
are hidden from its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderProcessing&lt;/code&gt; clients.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h2&gt;

&lt;p&gt;We showed how detecting some code smells and trying to remove them led us to a more cohesive and less coupled design.&lt;/p&gt;

&lt;p&gt;The initial code presented several code smells. We started by trying to remove the temporary field code smell but we didn’t 
find an easy way to remove it. The real obstacle to removing it was caused by other code smells: Feature envy and Solution Sprawl.&lt;/p&gt;

&lt;p&gt;Once we removed those smells moving to a more “Tell, don’t ask” style we had the whole responsibility of processing 
the order in one place and an interface that might be valid for all the different phases of the processing. Then it was 
easy to move to the state design pattern.&lt;/p&gt;

&lt;p&gt;The final code is more cohesive than the original one and explicitly represents the different phases of the order processing.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;I’d like to thank to my Codesai colleagues, &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and 
&lt;a href=&quot;https://www.linkedin.com/in/alfredo-casado/&quot;&gt;Alfredo Casado&lt;/a&gt; for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Also thanks to &lt;a href=&quot;https://es.audiense.com/&quot;&gt;Audiense&lt;/a&gt;’s developers for all their work they put in the deliberate practice 
sessions. I learn a lot with you.&lt;/p&gt;

&lt;p&gt;Finally I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@masudriguez/&quot;&gt;Masud Allahverdizade&lt;/a&gt; for his photo.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] We are giving this service to several companies.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] During our deliberate practice program we use a modified version of the kata in which 
we introduce other iterations which introduce interesting changes that force some preparatory refactorings 
or help to apply other concepts.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Solution Sprawl is a code smell described by &lt;a href=&quot;https://www.linkedin.com/in/joshuakerievsky/&quot;&gt;Joshua Kerievsky&lt;/a&gt; in his 
&lt;a href=&quot;https://www.industriallogic.com/refactoring-to-patterns/&quot;&gt;Refactoring To Patterns book&lt;/a&gt;: 
“when code and/or data used to perform a responsibility becomes sprawled across numerous classes”. 
Solution Sprawl and Shotgun Surgery address the same problem, a &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;Single Responsibility Principle&lt;/a&gt;
violation or lack of cohesion, but they are detected differently. Solution Sprawl is detected by observing it in the code, 
while Shotgun Surgery is detected when trying to change the code.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] I like how &lt;a href=&quot;https://twitter.com/thedrlambda&quot;&gt;Christian Clausen&lt;/a&gt; calls code using this 
“Tell don’t ask” style, &lt;em&gt;”push-based code”&lt;/em&gt;, as opposed to a &lt;em&gt;“pull-based code”&lt;/em&gt; or code using “ask” style that pulls 
all the data to a place, does all the calculations, and then delivers the results to somewhere else.
&lt;a href=&quot;https://martinfowler.com/aboutMe.html&quot;&gt;Martin Fowler&lt;/a&gt;’s &lt;a href=&quot;https://martinfowler.com/bliki/GetterEradicator.html&quot;&gt;Getter Eradicator&lt;/a&gt; post goes deeper into the 
“Tell don’t ask” style and the Feature Envy code smell, getting to the interesting rule of thumb that 
&lt;em&gt;“things that change together should be together”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] The Inappropriate Intimacy code smell is more general than accessing private members. It is about one class depending 
on the implementation details of another. Some examples of Inappropriate Intimacy are, for example, knowing that two public 
methods need to be called in a certain order because of some private implementation detail, 
or accessing a property to make sure that an object that loads lazily is initialised. 
See &lt;a href=&quot;https://www.youtube.com/watch?v=xa6aS9ObJTg&quot;&gt;Jason Gorman’s video about this code smell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/es-es/@masudriguez/&quot;&gt;Masud Allahverdizade&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2024-03-14T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2024/03/using-smells-to-go-oo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2024/03/using-smells-to-go-oo</guid>
        </item>
      
    
      
        <item>
          <title>&quot;Split or condition in if&quot; refactoring in TypeScript</title>
          <description>&lt;p&gt;In a &lt;a href=&quot;https://codesai.com/posts/2022/10/split-or-condition&quot;&gt;previous post&lt;/a&gt; we documented the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring. This refactoring works fine for most languages. Unfortunately, it may occasionally present some problems in TypeScript because of how its compiler works.&lt;/p&gt;

&lt;p&gt;After applying the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring, the resulting code will contain duplication, and there may be obsolete if statements containing either unreachable code or code that is always executed, that we will clean.&lt;/p&gt;

&lt;p&gt;If the resulting code contains any if statement whose boolean condition always evaluates to false, the TypeScript compiler will emit a &lt;a href=&quot;https://typescript.tv/errors/#TS2367&quot;&gt;TS2367 error&lt;/a&gt;, even though the code is functionally correct. We show an example of this problem in the following figure.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/typescript-compilation-error-when-split-or.png&quot; alt=&quot;Compiler error when a boolean expression always evaluates to false.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Compiler error when a boolean expression always evaluates to false.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In these cases, the code would not compile again, and as a consequence, the test won’t pass until we remove all the boolean conditions that always evaluate to false or indicate the compiler to ignore them using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-ignore&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-expect-error&lt;/code&gt;. This might be ok if there are only a few &lt;em&gt;TS2367 errors&lt;/em&gt;. If not, cleaning those expressions will take too much time editing without having any feedback from the tests.&lt;/p&gt;

&lt;h3&gt;Revised mechanics for TypeScript.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#-ts-nocheck-in-typescript-files&quot;&gt;From TypeScript 3.7 onward&lt;/a&gt;, we can add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-nocheck&lt;/code&gt; rule to the top of TypeScript files to disable semantic checks (before that version, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-nocheck&lt;/code&gt; only worked for JavaScript files).&lt;/p&gt;

&lt;p&gt;Using TypeScript’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-nocheck&lt;/code&gt; rule will help us getting a shorter feedback cycle again, when cleaning redundant code resulting from applying the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring that contains &lt;em&gt;TS2367 errors&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We only need to slightly modify the original &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring mechanics:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt; 
      Add  the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt; @ts-nocheck&lt;/code&gt; rule to the top of TypeScript files to disable semantic checks.&lt;/li&gt;
    &lt;li&gt;
      Apply &lt;a href=&quot;https://codesai.com/posts/2022/10/split-or-condition/#mechanics&quot;&gt;the original &lt;b&gt;Split or condition in if&lt;/b&gt; refactoring
            &lt;/a&gt;.
    &lt;/li&gt;
    &lt;li&gt;
      Remove obsolete if statements in small steps while being able to get feedback from the tests at any time. 
    &lt;/li&gt;
    &lt;li&gt; 
      Remove the  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt; @ts-nocheck&lt;/code&gt; rule to enable semantic checks again.
    &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the following video, we show an example of how using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ts-nocheck&lt;/code&gt; allows us to be able to keep refactoring the code in small steps after applying the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring.&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;0DWCSGSAGW8&quot;&gt;
    &lt;div data-id=&quot;0DWCSGSAGW8&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/0DWCSGSAGW8/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;h3&gt;Conclusion.&lt;/h3&gt;

&lt;p&gt;We described a problem that TypeScript developers will find when the code resulting after applying the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring contains any boolean condition that always evaluates to false which will produce &lt;em&gt;TS2367 errors&lt;/em&gt;, and we provided a way to fix it. Following revised &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring mechanics that we proposed, you will be able to keep refactoring in small steps to remove unreachable code left after applying the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring even when there are &lt;em&gt;TS2367 errors&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We hope this revision of the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring would be useful for TypeScript developers.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; for recording the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring video in this post, and for giving me feedback on the contents of this post.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.pexels.com/@yuliya-kota-2099022/&quot;&gt;Yuliya Kota&lt;/a&gt; for her photo.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;h3 id=&quot;articles&quot;&gt;Articles&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/posts/2022/10/split-or-condition&quot;&gt;“Split or condition in if” refactoring&lt;/a&gt;, &lt;a href=&quot;https://garajeando.blogspot.com/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://typescript.tv/errors/&quot;&gt;TypeScript errors and how to fix them&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html&quot;&gt;TypeScript 3.7 Release Notes&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/@yuliya-kota-2099022/&quot;&gt;Yuliya Kota&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2022-12-30T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/12/split-or-condition-in-ts</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/12/split-or-condition-in-ts</guid>
        </item>
      
    
      
        <item>
          <title>Caring Work and where to find it: concerns mechanism</title>
          <description>&lt;h2 id=&quot;caring-work&quot;&gt;Caring work.&lt;/h2&gt;

&lt;p&gt;In our previous &lt;a href=&quot;https://codesai.com/2020/06/caring&quot;&gt;post about caring work&lt;/a&gt; we described how the concept of caring work&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; had been very useful for us in the coaching work we did with several teams during all of 2019 and a big part of 2020.&lt;/p&gt;

&lt;p&gt;We used the concept of caring work to redefine the very concept of value in our client, so that producing features as quickly as possible (productive work) was not the only type of work considered valuable, and they started to also see value in work concerned with keeping the health of the ecosystem composed of the code, the team and the client (caring work), so that it can continue evolving, being habitable for the team and producing more value for its users. They understood that aside from productive work, we also needed to devote energy and time to caring work.&lt;/p&gt;

&lt;h2 id=&quot;how-did-we-apply-the-concept-of-caring-work&quot;&gt;How did we apply the concept of caring work?&lt;/h2&gt;

&lt;p&gt;The way to apply caring work in a team highly depends on the team’s context. Do not take this as “a recipe for applying caring work” or “the way to apply caring work”.&lt;/p&gt;

&lt;p&gt;In this post we mostly talk about our experience working with &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;’s Barcelona B2B team which was the first team we worked with inside &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;. We later introduced small local variations to adapt these ideas and mechanisms to the context of other &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;’s teams, and to their coaches.&lt;/p&gt;

&lt;p&gt;We took two main decisions&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;To protect a given percentage of time/effort in every iteration for caring work. The specific distribution of time/effort between the two types of work depended on the context of each of the teams we worked with&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Only developers could decide which caring work was needed.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-did-we-identify-caring-work&quot;&gt;How did we identify caring work?&lt;/h2&gt;

&lt;blockquote&gt;
&quot;A process cannot be understood by stopping it. Understanding must move with the flow of the process, must join it and flow with it.&quot;
— Frank Herbert
&lt;/blockquote&gt;

&lt;p&gt;A complex system is in constant flux, and any action may change the system in unpredictable ways. So after any change&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; we need to observe the new dynamics that start to form and apply suitable corrections. But, how could we sense the dynamics of the system in order to adapt to it?&lt;/p&gt;

&lt;p&gt;We decided to use a &lt;b&gt;concerns mechanism&lt;/b&gt; to detect system health problems and try to solve them as we went.&lt;/p&gt;

&lt;h3 id=&quot;the-concerns-mechanism&quot;&gt;The concerns mechanism.&lt;/h3&gt;

&lt;p&gt;A concern might be anything someone working on the system doesn’t understand, doesn’t agree with, thinks that might be problematic, or thinks that might be changed to improve the system’s sustainability. The concept of a concern&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; was described by &lt;a href=&quot;https://twitter.com/XaV1uzz&quot;&gt;Xavi Gost&lt;/a&gt; in his talk &lt;a href=&quot;https://www.youtube.com/watch?v=pp8j1ggCaoM&quot;&gt; Consensus-driven development (CDD)&lt;/a&gt;&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Consensus-driven development is based on the premise that developing software is a team endeavour, and on seeing the current system as an implicit representation of the real team’s consensus about what they are currently developing. This consensus will evolve to adapt to contextual changes. Not acknowledging this tacit consensus may cause problems in the team’s dynamics.&lt;/p&gt;

&lt;p&gt;The &lt;b&gt;concerns mechanism&lt;/b&gt; we used follows the process indicated in the next figure:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/concerns_mechanism_cycle.png&quot; alt=&quot;Concerns mechanism.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Concerns mechanism.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This mechanism gives the team a way to raise concerns about the current team’s consensus so they can be discussed. It also helps to make the actual team’s consensus about the system explicit.&lt;/p&gt;

&lt;p&gt;We find the &lt;b&gt;concerns mechanism&lt;/b&gt; very interesting because it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fosters technical conversations.&lt;/li&gt;
  &lt;li&gt;Serves as a space to manage conflicts and reach new agreements that make the current team’s consensus explicit.&lt;/li&gt;
  &lt;li&gt;Helps to transmit knowledge.&lt;/li&gt;
  &lt;li&gt;Detects waste in the part of the software value stream comprising development to delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We had found a way to sense the dynamics of the system.&lt;/p&gt;

&lt;p&gt;The concerns mechanism is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Kaizen&quot;&gt;kaizen&lt;/a&gt; process enriched with information from the people actually involved in the actual work. It helps to apply several &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development&quot;&gt;Lean Software Development&lt;/a&gt; principles, such as, &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development#Eliminate_waste&quot;&gt;Eliminate waste&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development#Amplify_learning&quot;&gt;Amplify Learning&lt;/a&gt; and  &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development#Empower_the_team&quot;&gt;Empower the team&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our goal was not only to improve the developers’ experience by creating an environment, practices, architecture and infrastructure in which the team members could learn and work better and with less stress&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;, we also wanted to develop the team’s technical skills.&lt;/p&gt;

&lt;p&gt;The concerns mechanism can be a great coaching tool. Since the technical coaches were outnumbered by the team members&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;, the concerns mechanism provided us a space to solve team members’ doubts and raise our own concerns about design decisions. This made it an additional after-the-fact coaching tool, which complemented other live coaching activities, such as, the ensemble and pair programming sessions we had with the team.&lt;/p&gt;

&lt;p&gt;In this coaching context, the discussion of concerns made more emphasis on learning than on reaching consensus, especially at the beginning of our work with the team. Later, as the team was more mature, the emphasis changed. The idea was that once we leave, the team could keep on using the concerns mechanism on their own to reach consensus and detect caring work.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/ConcernsAre.png&quot; alt=&quot;Concerns tool summary.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Concerns tool summary.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;concerns-collection-and-prioritisation&quot;&gt;Concerns collection and prioritisation.&lt;/h4&gt;

&lt;p&gt;During an iteration, the team raised concerns by describing each of them in cards that were added to a separate board dedicated to this purpose. Below you can see the concerns board of one the teams:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/trello_concerns_censurado.png&quot; alt=&quot;Concerns board.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Concerns board.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;At the end of the iteration, we had a fifteen-to-thirty-minutes meeting in which we prioritised the new concerns on the &lt;strong&gt;Pending to prioritize&lt;/strong&gt; column. We used three possible levels of priority: high, medium or low&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To prioritise a concern, after a brief explanation of the concern followed by some questions to clarify possible doubts, the team members responded in parallel to the question of “how important do you think discussing this particular concern is?”.&lt;/p&gt;

&lt;p&gt;A variant of the planning poker dynamics with only three cards with values 1, 2 or 3, which corresponded to low, medium and high priority, respectively&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt; helped us reach consensus about the priority. We used &lt;a href=&quot;https://www.planitpoker.com/&quot;&gt;PlanITPoker&lt;/a&gt; but any similar tool will do.&lt;/p&gt;

&lt;h4 id=&quot;concerns-discussion-and-outcomes&quot;&gt;Concerns discussion and outcomes.&lt;/h4&gt;

&lt;p&gt;Once a week we held a one-hour meeting to discuss the concerns with higher priority. For each concern card, the team members that had raised it, explained further the concern’s description, and answered any doubts that the rest of the team might have about the concern. Sometimes, other team members provided information about similar problems they had observed in other parts of the system.&lt;/p&gt;

&lt;p&gt;After understanding the concern better, we discussed it for a while to try to determine its possible causes and effects, then, we proposed and discussed possible ways of solving or, at least, mitigating the concern. In these discussions, we tried to reach consensus and good enough/pragmatic ways to address each concern. In order to foster the team’s sense of agency and autonomy, we focused on what it could control and change at any given moment. However, sometimes, this was not enough and we had to escalate the concerns to higher levels, with the intention of somehow modifying organisational constraints or policies that were affecting the team.&lt;/p&gt;

&lt;p&gt;Depending on the specific concern, the team obtained different outcomes from its discussion (often several of them at the same time):&lt;/p&gt;

&lt;p&gt;a. &lt;b&gt;Learning about new concepts&lt;/b&gt; (code smells, antipatterns, design principles, patterns, techniques, tools, etc). Sometimes, the coaches helped the team, and other times the team members taught each other.&lt;/p&gt;

&lt;p&gt;b. &lt;b&gt;Reflecting on the current consensus of the team&lt;/b&gt;, thus, making it more explicit and transmitting it to everyone.&lt;/p&gt;

&lt;p&gt;c. &lt;b&gt;Evolving the current consensus of the team&lt;/b&gt; by getting to new agreements or revising old ones.&lt;/p&gt;

&lt;p&gt;d. &lt;b&gt;Detecting caring work to be done&lt;/b&gt;. The detected caring work was recorded and described in &lt;b&gt;caring tasks&lt;/b&gt; cards that we collected in a different board. The caring tasks might be very varied depending on the nature of concerns that originated them. Some consisted of research in the form of &lt;b&gt;experiments&lt;/b&gt;&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt;, others resulted in internal trainings, and others were efficiency improvements of any kind (paying technical debt in code, infrastructure or architecture, writing documentation, improving the ubiquitous language, etc). Anything that we needed to keep our system healthy.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/ConcernsOutcomes.png&quot; alt=&quot;Concerns discussion outcomes.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Concerns discussion outcomes.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In the following figure we show an example of the modification of a previously existing agreement after discussing a concern.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/concern_con_revision_de_agreement.png&quot; alt=&quot;Example of reaching a new consensus after discussing a concern.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Example of reaching a new consensus after discussing a concern.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Notice how we recorded the new agreement as a comment in the &lt;a href=&quot;https://trello.com&quot;&gt;Trello&lt;/a&gt; card. We think that it might be more useful to document these agreements that make the consensus explicit in &lt;b&gt;Consensus Records, (CRs)&lt;/b&gt; that might follow a format similar to the &lt;a href=&quot;https://adr.github.io/&quot;&gt;Architectural Decision Records, (ADRs)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following figure shows a caring task produced after discussing a concern about an action that had accumulated too many collaborators, and recorded how the team had decided that they could reduce the number of collaborations and remove some duplication:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/caring_task_example_1.png&quot; alt=&quot;Example of a caring task originated by the discussion of a concern.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Example of a caring task originated by the discussion of a concern.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;why-did-we-decide-to-discuss-concerns-in-a-dedicated-meeting-instead-of-using-the-retrospective&quot;&gt;Why did we decide to discuss concerns in a dedicated meeting instead of using the retrospective?&lt;/h3&gt;

&lt;p&gt;Retrospectives are also a meeting that provides a space to reflect and learn, in order to improve the efficiency of a team. They ideally include all the people that might help finding better ways of delivering value (product, tech, ux…). Why not use them, then?&lt;/p&gt;

&lt;p&gt;We’d like to start by stating that by no means the concerns meeting should substitute retrospectives. These meetings have different, though sometimes a bit overlapping, scopes. We think that they are both useful and should be complementary.&lt;/p&gt;

&lt;p&gt;Still, there are reasons why we think that concerns should be discussed in a different meeting than the retrospective.&lt;/p&gt;

&lt;p&gt;On one hand, there’s the matter of who can best contribute to the discussion and of not wasting people’s time in unnecessary meetings. As we described earlier, concerns are a way to detect waste in the part of the software value stream comprising development to delivery. This means that most concerns are technical in nature, so for most of the discussions there would be no point in having non technical people in the meeting as this would waste their time.  We think that this is true, regardless of having or not a healthy dynamic between product and engineering.&lt;/p&gt;

&lt;p&gt;On the other hand, we wanted to protect the team’s autonomy to decide which caring work to do because they are the ones that work with the system and know where the friction and inefficiencies are happening, and have better information to fix them. We think that this makes sense from the point of view of the lean principle of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development#Empower_the_team&quot;&gt;Empowering the team&lt;/a&gt;. Besides, the DevOps movement also defends that engineering should spend the time devoted to caring work as they see fit&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt; (which for them amounts to at least 20% of the team’s time).&lt;/p&gt;

&lt;p&gt;Besides, the cultural dynamic around the B2B team when we started working with them, was characterised by a strong power imbalance between the product and engineering teams which left the latter little autonomy and agency. In order to create a space safe from this vicious dynamic, we decided to discuss the concerns in a separate meeting in which only the members of the engineering team could participate. This strong boundary fostered the autonomy of the engineering team and made caring work possible&lt;a href=&quot;#nota13&quot;&gt;&lt;sup&gt;[13]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having said that, some concerns needed a different approach.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Concerns that went beyond what the engineering team could control and change, or that required knowledge that the members of the team didn’t have yet. In those cases, we either invited whoever could provide the needed information to the concerns meeting, or took the specific concern to the retrospective.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Concerns caused by blocks due to how the company organised the teams. These kinds of problems related to &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_law&quot;&gt;Conway’s Law&lt;/a&gt; are very hard to fix, and their symptoms can at best be mitigated within the team. We took those concerns to the retrospective as a first step to gather more information before escalating them.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary·&lt;/h2&gt;

&lt;p&gt;In this post we have explained how we applied the concept of caring work in several teams of &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt; for more than a year. Remember that the application of this concept depends on the team’s context. Do not take this as “a recipe for applying caring work” or “the way to apply caring work”.&lt;/p&gt;

&lt;p&gt;We, first, showed how we created a safe space for caring work by devoting a given percentage of time/effort to it in every iteration, and by giving autonomy and agency to developers to decide which caring work was needed.&lt;/p&gt;

&lt;p&gt;Then we showed how we applied the concerns mechanism to identify caring work and improve consensus about the system and communication in the team. The concerns mechanism also proved to be a great after-the-fact coaching tool that complemented other live coaching tools we were using.&lt;/p&gt;

&lt;p&gt;We also described how we collected, prioritised and discussed concerns each iteration, and talked about the different outcomes we got from discussing concerns.&lt;/p&gt;

&lt;p&gt;Finally, we gave our reasons for using a separate meeting to discuss concerns instead of using the retrospective.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;’s Barcelona B2B team, for all the effort and great work they did to make the concerns mechanism work for them. That great work made it much easier for other teams in &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt; to start applying the idea of caring work with the help of other Codesai coaches.&lt;/p&gt;

&lt;p&gt;Also thanks to my Codesai colleagues, &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/rub%C3%A9n-d%C3%ADaz-mart%C3%ADnez-b9276395/&quot;&gt;Rubén Díaz&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/danielojedaloisel/&quot;&gt;Dani Ojeda&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt;, for giving me feedback about several drafts of this post.&lt;/p&gt;

&lt;p&gt;Finally I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@karolina-grabowska/&quot;&gt;Karolina Grabowska&lt;/a&gt; for her photo.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Idea from economic studies from a gender perspective where caring work is defined as “those occupations that provide services that help people develop their capabilities, or the ability to pursue the aspects of their lives that they value” and “necessary occupations and care to sustain life and human survival”.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] We didn’t know it when we took these decisions but they were aligned with the recommendations of the DevOps movement, as you can see in the following quotes:&lt;/p&gt;

&lt;p&gt;“We will actively manage this technical debt by ensuring that we invest at least 20% of all Development and Operations cycles on refactoring, investing in automation work and architecture and non-functional requirements (NFRs, sometimes referred to as the “ilities”), such as maintainability, manageability, scalability, reliability, testability, deployability, and security.”
— &lt;a href=&quot;https://www.goodreads.com/book/show/26083308-the-devops-handbook&quot;&gt;The DevOps Handbook&lt;/a&gt;&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/devops_handbook_ch_061.png&quot; alt=&quot;Invest 20% of cycles on those that create positive user-invisible value from The DevOps Handbook.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;&quot;Invest 20% of cycles on those that create positive user-invisible value” from The DevOps Handbook.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] The first team we worked with devoted 20% of their time to caring work and 80% to productive work. Other teams that later worked with us distributed the work in different proportions (never less than 20% to caring work).&lt;/p&gt;

&lt;p&gt;Note that 20% is the minimum recommended in &lt;a href=&quot;https://www.goodreads.com/book/show/26083308-the-devops-handbook&quot;&gt;The DevOps Handbook&lt;/a&gt; to keep a healthy system:&lt;/p&gt;

&lt;p&gt;The DevOps Handbook authors quote Marty Cagan’s book &lt;a href=&quot;https://www.goodreads.com/book/show/35249663-inspired&quot;&gt;Inspired: How To Create Products Customers Love&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;According to Cagan, “Product management takes 20% of the team’s capacity right off the top and gives this to engineering to spend as they see fit.”&lt;/p&gt;

&lt;p&gt;“Cagan notes that when organizations do not pay their “20% tax,” technical debt will increase to the point where an organization inevitably spends all of its cycles paying down technical debt.”
— &lt;a href=&quot;https://www.goodreads.com/book/show/26083308-the-devops-handbook&quot;&gt;The DevOps Handbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“By dedicating 20% of our cycles so that Dev and Ops can create lasting countermeasures  to the problems we encounter in our daily work, we ensure that technical debt doesn’t impede our ability to quickly and safely develop and operate our services in production.”
— &lt;a href=&quot;https://www.goodreads.com/book/show/26083308-the-devops-handbook&quot;&gt;The DevOps Handbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to Cagan again, “if you’re in really bad shape today, you might need to make this 30% or even more of the resources. However, I get nervous when I find teams that think they can get away with much less than 20%”. This aligns with what we had to propose in some other teams we coached in &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] With the intention of unlocking the system from its initial dynamics, we started by applying several changes to how the team worked. These initial changes were related to the change levers we had identified in the team’s dynamics. Read about them in our previous post about caring work: &lt;a href=&quot;https://codesai.com/2020/06/caring&quot;&gt;The value of caring&lt;/a&gt;, &lt;a href=&quot;https://garajeando.blogspot.com/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] At first, we thought we had widened Xavi’s definition of concern. In his talk, he focused mostly on concerns in code as a way to avoid blocking code reviews. Instead, we decided to raise concerns about any inefficiency or waste that we observed in the part of the software value stream comprising development to delivery. Later in a personal conversation with &lt;a href=&quot;https://twitter.com/borillo?lang=en&quot;&gt;Ricardo Borillo&lt;/a&gt;, who was researching how concerns are used in the wild, we discovered that they (Xavi and Ricardo) are using concerns in the same way we are, but Xavi did not manage to transmit this in his talk because of excessively focusing on code reviews.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] The talk about Consensus Driven Development is in Spanish.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt;  [7]  These ideas are related to &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_P._Gabriel&quot;&gt;Richard Gabriel&lt;/a&gt;’s idea of &lt;a href=&quot;https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf&quot;&gt;software habitability&lt;/a&gt;, and &lt;a href=&quot;https://www.linkedin.com/in/alexandrubolboaca/&quot;&gt;Alexandru Bolboaca&lt;/a&gt;’s ideas in his book &lt;a href=&quot;https://leanpub.com/usablesoftwaredesign&quot;&gt;Usable software Design&lt;/a&gt;. We think, both, are in turn,  based on &lt;a href=&quot;https://en.wikipedia.org/wiki/W._Edwards_Deming&quot;&gt;Deming&lt;/a&gt;’s idea that a system has a huge influence on a person’s performance:&lt;/p&gt;

&lt;blockquote&gt;
&quot;A Bad System Will Beat a Good Person Every Time.&quot; 
— W. Edwards Deming
&lt;/blockquote&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] At the beginning only &lt;a href=&quot;https://www.linkedin.com/in/franreyesperdomo/&quot;&gt;Fran Reyes&lt;/a&gt; and I worked with &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;’s Barcelona B2B team. Even though we later got more critical mass when &lt;a href=&quot;https://www.linkedin.com/in/antoniodelatorre/&quot;&gt;Antonio de la Torre&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/mjtordesillas/&quot;&gt;Manuel Tordesillas&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/alvarobiz&quot;&gt;Álvaro García&lt;/a&gt; joined the team, by that time the B2B team had already doubled in size, so we still were outnumbered.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] We decided to use only three levels of priority following the early three categories of &lt;a href=&quot;https://en.wikipedia.org/wiki/Triage#History&quot;&gt;triage in medicine&lt;/a&gt;. Some teams decided to use prioritisation models with more categories, but it resulted in a lot of confusion at the time of prioritising. We think it’s better to keep it simple and use only the three categories mentioned: high, medium and low.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] We like the poker planning dynamics because it is a quick and simple diverge-and-converge collaboration method that helps reduce &lt;a href=&quot;https://en.wikipedia.org/wiki/Information_cascade&quot;&gt;information cascades&lt;/a&gt; in the team due to power differential and anchoring.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] Experiments consisted of researching alternative solutions or tools that we might use to address a concern. We called them experiments to explicitly distinguish them from &lt;a href=&quot;https://en.wikipedia.org/wiki/Spike_(software_development)&quot;&gt;spikes&lt;/a&gt;, so that we avoided the usage of caring work time for spikes which, we think, should be used to reduce uncertainty in features.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12] They don’t use the term caring work, but they mean the same, “not working on features”.&lt;/p&gt;

&lt;p&gt;The DevOps Handbook quotes Marty Cagan arguing about the kind of work that the team might do in that 20%:, “Product management takes 20% of the team’s capacity right off the top and &lt;b&gt;gives this to engineering to spend as they see fit&lt;/b&gt;. They &lt;b&gt;might use it to rewrite, re-architect, or refactor problematic parts of the code base&lt;/b&gt;… &lt;b&gt;whatever they believe is necessary to avoid ever having to come to the team and say, ‘we need to stop and rewrite&lt;/b&gt; [all our code].”&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota13&quot;&gt;&lt;/a&gt; [13]  Later this strong boundary was exported to other teams due to similar power dynamics, but this doesn’t mean that this might be necessary in every context. Depending on the culture and people involved the retrospective might be enough.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;h3 id=&quot;books&quot;&gt;Books&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/en/book/show/31623180-usable-software-design&quot;&gt;Usable Software Design&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf&quot;&gt;Patterns of Software: Tales from the Software Community&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_P._Gabriel&quot;&gt;Richard P. Gabriel&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/194338.Lean_Software_Development&quot;&gt;Lean Software Development: An Agile Toolkit&lt;/a&gt;, &lt;a href=&quot;http://www.poppendieck.com/people.htm&quot;&gt;Mary Poppendieck and Tom Poppendieck&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/26083308-the-devops-handbook&quot;&gt;The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations&lt;/a&gt;, 
&lt;a href=&quot;https://twitter.com/RealGeneKim&quot;&gt;Gene Kim&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/jezhumble&quot;&gt;Jez Humble&lt;/a&gt;, &lt;a href=&quot;http://www.jedi.be/blog/&quot;&gt;Patrick Debois&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/johnwillisatlanta/&quot;&gt;John Willis&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.infoq.com/minibooks/cynefin-mini-book/&quot;&gt;The Cynefin mini book&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/sailinggreg&quot;&gt;Greg Brougham&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Accelerate_(book)&quot;&gt;Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Nicole_Forsgren&quot;&gt;Nicole Forsgren Velasquez&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/jez-humble/&quot;&gt;Jez Humble&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/realgenekim/&quot;&gt;Gene Kim&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;articles&quot;&gt;Articles&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/2020/06/caring&quot;&gt;The value of caring&lt;/a&gt;, &lt;a href=&quot;https://garajeando.blogspot.com/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talks&quot;&gt;Talks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=B31QrNFyRyc&quot;&gt;Code Blindness&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mfeathers&quot;&gt;Michael Feathers&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=pp8j1ggCaoM&quot;&gt;CDD (Desarrollo dirigido por consenso)&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/XaV1uzz&quot;&gt;Xavi Gost&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=N7oz366X0-8&quot;&gt;The Cynefin Framework&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Dave_Snowden&quot;&gt;Dave Snowden&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;podcasts--interviews&quot;&gt;Podcasts &amp;amp; Interviews&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.thebigbranchtheory.dev/post/caring-task-deuda-tecnica-manuel-rivero/&quot;&gt;Caring Task con Manuel Rivero, Parte 1&lt;/a&gt;, &lt;a href=&quot;https://www.thebigbranchtheory.dev/&quot;&gt;The Big Branch Theory Podcast&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.thebigbranchtheory.dev/post/caring-task-deuda-tecnica-manuel-rivero-parte-2/&quot;&gt;Caring Task con Manuel Rivero, Parte 2&lt;/a&gt;, &lt;a href=&quot;https://www.thebigbranchtheory.dev/&quot;&gt;The Big Branch Theory Podcast&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Sk3JfHF6BWU&quot;&gt;Entrevista de Agile Alliance a Antonio de la Torre: El valor de las tareas de cuidado en nuestro entorno&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/es-es/@karolina-grabowska/&quot;&gt;Karolina Grabowska in Pexels&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2022-11-30T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/11/caring-work-and-concerns</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/11/caring-work-and-concerns</guid>
        </item>
      
    
      
        <item>
          <title>On code smells catalogues and taxonomies</title>
          <description>&lt;p&gt;This post is an English translation of the original post: &lt;a href=&quot;https://codesai.com/posts/2022/09/code-smells-taxonomies-and-catalogs&quot;&gt;De taxonomías y catálogos de code smells&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction: code smells and refactoring.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#martin_fowler_catalog&quot;&gt;Martin Fowler: code smells and catalogues.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#taxonomies&quot;&gt;Taxonomies.&lt;/a&gt;&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#wake_taxonomy&quot;&gt;Wake’s taxonomy 2003.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mantyla_taxonomy_2003&quot;&gt;Mäntylä et al taxonomy 2003.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mantyla_taxonomy_2006&quot;&gt;Mäntylä et al  taxonomy 2006.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#jerzyk_taxonomy_2022&quot;&gt;Jerzyk et al  taxonomy 2022.&lt;/a&gt;&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#jerzyk_code_smells&quot;&gt;Jerzyk’s extended code smells catalogue.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#jerzyk_code_smell_online_catalog&quot;&gt;Online catalogue.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;Conclusions.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#acknowledgements&quot;&gt;Acknowledgements.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#references&quot;&gt;References.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a name=&quot;introduction&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt; Introduction: code smells and refactoring.&lt;/h2&gt;

&lt;p&gt;Refactoring is a practice that allows us to sustainably evolve code. To refactor problematic code, we first need to be able to recognize it.&lt;/p&gt;

&lt;p&gt;Code smells are descriptions of signals or symptoms that warn us of possible design problems. It’s crucial to detect these problems and remove them as soon as possible.&lt;/p&gt;

&lt;p&gt;Refactoring is cheaper and produces better results when done regularly. The longer a problematic piece of code lives, the more it takes to refactor it, and the biggest friction it will add to evolve new features directly contributing to accruing technical debt. Sustaining this situation over a long period of time may have a very negative economic impact. In the worst case scenario, the code might get too complicated to keep on maintaining it.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_feature_cost_vs_time.png&quot; alt=&quot;Cost of introducing a feature over time&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Cost of introducing a feature over time (image from The Three Values of Software from J. B. Rainsberger).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Another, sometimes not so visible, consequence of bad software quality is its effects on developers. Less refactoring, can lead to a less maintainable code that can lead to longer times to develop new features, which, in turn, means more time pressure to deliver, which can lead us to test less, which will allow us to refactor less… This vicious circle might have a very demoralising effect.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_vicious_cycle.png&quot; alt=&quot;Less refactoring vicious circle&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Less refactoring vicious circle.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Understanding and being able to identify code smells gives us the opportunity of detecting design problems when they are still small and located in specific areas of our code, and, as such, are still easy to fix. This might have a very positive economic and emotional effect.&lt;/p&gt;

&lt;p&gt;The problem is that code smells are not usually  very well understood. This problem is understandable because code smells descriptions are sometimes abstract, diffuse and open to interpretation. Some code smells seem obvious, others not so much, and some might mask other smells.&lt;/p&gt;

&lt;p&gt;Besides, we should remember that smells are only symptoms of possible design problems, not guarantees of the existence of problems. To further complicate matters, in addition to possible false positives, there are degrees to the problem that each smell represents, trade-offs between different smells and contraindications in their refactorings (sometimes “the cure is worse than the disease”).&lt;/p&gt;

&lt;p&gt;Therefore, recognizing design problems through code smells is a subtle skill that requires experience and judgement. Acquiring this skill, which sometimes may feel like a kind of spider-sense, can take some time.&lt;/p&gt;

&lt;p&gt;In our experience teaching and coaching teams, not being able to identify code smells is one of the greatest barriers to refactoring. Many developers do not detect design problems while they are still small and localised. What we often observe is that they don’t sense the design problems until the problems are quite large and/or have compounded with other problems, spreading through their codebase.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;martin_fowler_catalog&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;code-smells-catalogues&quot;&gt;Code smells catalogues.&lt;/h2&gt;

&lt;p&gt;In 1999 Fowler and Beck published a code smells catalogue in a chapter of the book,
&lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;. This catalogue contains the descriptions of 22 code smells.&lt;/p&gt;

&lt;p&gt;In 2018 Fowler published a &lt;a href=&quot;https://www.goodreads.com/book/show/35135772-refactoring&quot;&gt;second edition of his book&lt;/a&gt;. In this new edition there are a number of changes with respect to the first, mainly in the code smells catalogue of smells and the refactorings catalogue (detailed in &lt;a href=&quot;https://martinfowler.com/articles/refactoring-2nd-changes.html&quot;&gt;Changes for the 2nd Edition of Refactoring&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If we focus on the smells, which is the goal of this post, the changes are as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Four new code smells are introduced: &lt;em&gt;Mysterious Name&lt;/em&gt;, &lt;em&gt;Global Data&lt;/em&gt;, &lt;em&gt;Mutable Data&lt;/em&gt; and &lt;em&gt;Loops&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Two code smells are removed: &lt;em&gt;Parallel Inheritance Hierarchies&lt;/em&gt; and &lt;em&gt;Incomplete Library Class&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;And four code smells are renamed: &lt;em&gt;Lazy Class&lt;/em&gt; becomes &lt;em&gt;Lazy Element&lt;/em&gt;, &lt;em&gt;Long Method&lt;/em&gt; becomes &lt;em&gt;Long Function&lt;/em&gt;, &lt;em&gt;Inappropriate Intimacy&lt;/em&gt; becomes &lt;em&gt;Insider Trading&lt;/em&gt;, and &lt;em&gt;Switch Statement&lt;/em&gt; becomes &lt;em&gt;Repeated Switches&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are 24 code smells in total. Even though they usually have catchy and memorable names, it’s difficult to remember such a long list.&lt;/p&gt;

&lt;p&gt;How could we better understand code smells? How could we remember them more easily?&lt;/p&gt;

&lt;p&gt;In this post, and some later ones, we will talk about strategies to better understand and remember code smells.&lt;/p&gt;

&lt;h2 id=&quot;organisational-strategies&quot;&gt;Organisational strategies.&lt;/h2&gt;

&lt;p&gt;Organising and manipulating information, seeing it from different points of view, can help us understand and remember it better. Taxonomies are a type of organisational strategy that allows us to group study material according to its meaning. This helps to create significant groupings of information or “&lt;em&gt;chunks&lt;/em&gt;” that will facilitate learning.&lt;/p&gt;

&lt;p&gt;As we mentioned, the 2018 Fowler catalogue is a flat list that does not provide any type of classification. Although, reading the descriptions of the code smells, and the motivation sections of the different refactorings, we can glimpse that some smells are more related to each other than to other smells, these relationships are not expressed explicitly and remain blurred and dispersed in different parts of the book.&lt;/p&gt;

&lt;p&gt;The use of taxonomies to classify similar code smells can be beneficial to better understand and remember code smells, and recognize the relationships that exist between them.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;taxonomies&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;taxonomies&quot;&gt;Taxonomies.&lt;/h2&gt;

&lt;p&gt;There have been different attempts to classify code smells according to different criteria. The most popular classification is that of Mäntylä et al 2006 but it is not the first one. Below we will show some taxonomies that we consider quite interesting.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;wake_taxonomy&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;wake-2003&quot;&gt;Wake 2003.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://xp123.com/articles/&quot;&gt;Wake&lt;/a&gt; in his book, &lt;a href=&quot;https://xp123.com/articles/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;, describes 9 new code smells that did not appear in Fowler’s original catalogue: &lt;em&gt;Dead Code&lt;/em&gt;, &lt;em&gt;Null Check&lt;/em&gt;, &lt;em&gt;Special Case&lt;/em&gt;, &lt;em&gt;Magic Number&lt;/em&gt;, &lt;em&gt;Combinatorial Explosion&lt;/em&gt;, &lt;em&gt;Complicated Boolean Expression&lt;/em&gt;, and three related to bad names: &lt;em&gt;Type Embedded in Name&lt;/em&gt;, &lt;em&gt;Uncommunicative Names&lt;/em&gt; and &lt;em&gt;Inconsistent Names&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Wake explicitly classifies code smells by first dividing them into two broad categories, &lt;em&gt;Smells within Classes&lt;/em&gt; and &lt;em&gt;Smells Between Classes&lt;/em&gt;, depending, respectively, on whether the code smell can be observed from within a class or whether a broader context needs to be considered (various classes). Each of these categories is divided into subcategories that group code smells based on where they can be detected. This classification criterion, later called &lt;em&gt;“occurrence”&lt;/em&gt; by Jerzyk, answers the question: “where does this code smell appear?”.&lt;/p&gt;

&lt;p&gt;Following this &lt;em&gt;“occurrence”&lt;/em&gt; criterion Wake finds 10 subcategories.&lt;/p&gt;

&lt;p&gt;Within the category of &lt;em&gt;Smells within Classes&lt;/em&gt; we find the following subcategories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Measured Smells&lt;/strong&gt;: code smells that can be easily identified with simple length metrics.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Names&lt;/strong&gt;: code smells that create semantic confusion and affect our ability to create mental models that help us understand, remember, and reason about code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unnecessary Complexity&lt;/strong&gt;: code smells related to unnecessary code that adds mental load and complexity. Dead code, &lt;a href=&quot;https://martinfowler.com/bliki/Yagni.html&quot;&gt;YAGNI&lt;/a&gt; violations, and accidental complexity.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Duplication&lt;/strong&gt;: developer’s nemesis. These code smells generate more code to maintain (cognitive and physical load), increase error proneness, and make it difficult to understand the code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Conditional Logic Smells&lt;/strong&gt;: code smells that complicate conditional logic making it difficult to reason about and change, and increasing error proneness. Some of them are weak substitutes for object-oriented mechanisms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The subcategories within the &lt;strong&gt;Smells between Classes&lt;/strong&gt; category are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Data&lt;/strong&gt;: code smells in which we find either pseudo objects (data structures without behaviour), or we find that some missing abstraction is missing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;: code smells related to misuse of inheritance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Responsibility&lt;/strong&gt;: code smells related to a bad assignment of responsibilities.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Accommodating Change&lt;/strong&gt;: code smells that manifest when we encounter a lot of friction when introducing changes. They are usually caused by combinations of other code smells.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Library Classes&lt;/strong&gt;: code smells related to the use of third-party libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_wake_map.png&quot; alt=&quot;Wake’s taxonomy 2003&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Wake’s taxonomy (new code smells appear in green).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Wake presents each smell in a standard format with the following sections: &lt;strong&gt;Smell&lt;/strong&gt; (the name and aliases), &lt;strong&gt;Symptoms&lt;/strong&gt; (clues that may help detect it), &lt;strong&gt;Causes&lt;/strong&gt; (notes on how it may have generated), &lt;strong&gt;What To Do&lt;/strong&gt; (possible refactorings), &lt;strong&gt;Benefits&lt;/strong&gt; (how the code will improve by removing it) and &lt;strong&gt;Contraindications&lt;/strong&gt; (false positives and trade-offs). In some cases, he adds notes relating the code smell to design principles that might have helped to avoid it.&lt;/p&gt;

&lt;p&gt;The book also contains many practical exercises and very useful tables (symptoms vs. code smells, smells vs. refactorings, reverse refactorings, etc.) and exercises that relate code smells to other concepts such as design principles or design patterns.&lt;/p&gt;

&lt;p&gt;We highly recommend reading this book to delve into the discipline of refactoring and better understand when and why to apply the refactorings that appear in Fowler’s catalogue.&lt;/p&gt;

&lt;p&gt;Although we also refer to to the rest of the taxonomies that we talk about in this post, the content about code smells in our course &lt;a href=&quot;https://codesai.com/cursos/refactoring/&quot;&gt;Code Smells &amp;amp; Refactoring&lt;/a&gt; is mainly based on Wake’s taxonomy seasoned with a bit of our own experience.
&lt;a name=&quot;mantyla_taxonomy_2003&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mäntylä-et-al-2003&quot;&gt;Mäntylä et al 2003.&lt;/h3&gt;

&lt;p&gt;In this taxonomy, code smells are grouped according to the effect they have on code (the type of problem, what they make difficult or the practices or principles that they break). This classification criteria is called “&lt;em&gt;obstruction&lt;/em&gt;” by Jerzyk 2022.&lt;/p&gt;

&lt;p&gt;The original classification from 2003 (&lt;a href=&quot;https://www.researchgate.net/publication/4036832_A_Taxonomy_and_an_Initial_Empirical_Study_of_Bad_Smells_in_Code&quot;&gt;A Taxonomy and an Initial Empirical Study of Bad Smells in Code&lt;/a&gt;) is comprised of 7 code smells categories: &lt;em&gt;Bloaters&lt;/em&gt;, &lt;em&gt;Object -Orientation Abusers&lt;/em&gt;, &lt;em&gt;Change Preventers&lt;/em&gt;, &lt;em&gt;Dispensables&lt;/em&gt;, &lt;em&gt;Encapsulators&lt;/em&gt;, &lt;em&gt;Couplers&lt;/em&gt; and &lt;em&gt;Others&lt;/em&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_mantyla_2003.png&quot; alt=&quot;Mäntylä et al taxonomy 2003&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mäntylä et al taxonomy 2003.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is how they define each of the categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Bloaters&lt;/strong&gt;: this category of smells represents something in the code that has grown so large that it can no longer be handled effectively.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Object-Orientation Abusers&lt;/strong&gt;: this category of smells relates to cases where the solution does not fully exploit the potential of object-oriented design.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Change Preventers&lt;/strong&gt;: this category refers to code structures that make it very difficult to change the code.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dispensable&lt;/strong&gt;: these smells represent something unnecessary that should be removed from the code.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Encapsulators&lt;/strong&gt;: this category has to do with communication mechanisms or data encapsulation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Couplers&lt;/strong&gt;: these smells represent cases of tight coupling, which goes against object-oriented design principles&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Others&lt;/strong&gt;: this category contains the remaining code smells (&lt;em&gt;Comments&lt;/em&gt; and 
&lt;em&gt;Incomplete Library Class&lt;/em&gt;) that did not fit into any of the previous categories.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In their paper, Mäntylä et al discuss the reasons why each code smell is in a given category and not another, although they admit that some of them could be classified in more than one category.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;mantyla_taxonomy_2006&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mäntylä-et-al-2006&quot;&gt;Mäntylä et al 2006.&lt;/h3&gt;

&lt;p&gt;In 2006 Mäntylä et al published another paper (&lt;a href=&quot;https://scholar.google.es/citations?view_op=view_citation&amp;amp;hl=es&amp;amp;user=rQHJ67UAAAAJ&amp;amp;citation_for_view=rQHJ67UAAAAJ:IjCSPb-OGe4C&quot;&gt;Subjective evaluation of software evolvability using code smells: An empirical study&lt;/a&gt;) in which they revised their original classification from 2003.&lt;/p&gt;

&lt;p&gt;In this new version, they eliminated the &lt;strong&gt;Encapsulators&lt;/strong&gt; (moving the &lt;em&gt;Message Chains&lt;/em&gt; and &lt;em&gt;Middle Man&lt;/em&gt; smells to the &lt;strong&gt;Couplers&lt;/strong&gt; category) and &lt;strong&gt;Others&lt;/strong&gt; (&lt;em&gt;Comments&lt;/em&gt; and &lt;em&gt;Incomplete Library Class&lt;/em&gt; disappear from the taxonomy) categories, and moved the &lt;em&gt;Parallel Inheritance Hierarchies&lt;/em&gt; code smell from the &lt;strong&gt;Object-Orientation Abusers&lt;/strong&gt; category to the &lt;strong&gt;Change Preventers&lt;/strong&gt; category.&lt;/p&gt;

&lt;p&gt;This version of their taxonomy is the one that has become most popular on the internet (it can be found on many websites, courses and posts), probably due to the greater accessibility (readability) of the summary of the paper that appears on the web: &lt;a href=&quot;https://mmantyla.github.io/BadCodeSmellsTaxonomy&quot;&gt;A Taxonomy for “Bad Code Smells”&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_mantyla_2006.jpg&quot; alt=&quot;Mäntylä et al taxonomy 2006&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mäntylä et al taxonomy 2006.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;What is interesting is not so much the discussion of which category each smell should fall into, but rather to start thinking that a given smell can have different types of effects on the code and the relationships between these effects. In fact, subsequent classifications from the point of view of the effect of a smell on the code (“&lt;em&gt;obstruction&lt;/em&gt;”) consider it more useful not to lose the information that a code smell can produce several effects. This leads to no longer considering categories as exclusive, which makes it possible that the same smell can fall into several categories.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_taxonomy_2022&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;jerzyk-et-al-2022&quot;&gt;Jerzyk et al 2022.&lt;/h3&gt;

&lt;p&gt;In 2022 Marcel Jerzyk published his master’s thesis, &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Code Smells: A Comprehensive Online
Catalog and Taxonomy&lt;/a&gt; and a &lt;a href=&quot;https://github.com/Luzkan/smells/blob /main/docs/paper.pdf&quot;&gt;paper with the same title&lt;/a&gt;. His research on code smells had three goals:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Providing a public catalogue that could be useful as a unified knowledge base for both researchers and developers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Identifying all the possible concepts that are being characterised as code smells and determining possible controversies about them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Assigning appropriate properties to code smells in order to characterise them.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To achieve these objectives, they carried out a review of the existing literature on code smells up to that moment, with special emphasis on code smell taxonomies.&lt;/p&gt;

&lt;p&gt;In the thesis 56 code smells are identified and described, of which 16 are new original proposals (remember that Wake described 31 code smells and Fowler 24 in his last review).&lt;/p&gt;

&lt;p&gt;Descriptions and discussions of each of these 56 code smells can be found in &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Jerzyk’s master’s thesis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Analysing the classification criteria of the taxonomies proposed up to that moment, Jerzyk finds three significant criteria to categorise code smells:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Obstruction&lt;/strong&gt;: this is the criterion used by Mäntylä et al to classify smells in their taxonomy, it’s also the most popular criterion. It informs us about the type of problem that a code smell causes in the code (what they make difficult or the practices or principles that they break). In the thesis they update the Mäntylä taxonomy, adding three new groups: &lt;strong&gt;Data Dealers&lt;/strong&gt;, &lt;strong&gt;Functional Abusers&lt;/strong&gt; and &lt;strong&gt;Lexical Abusers&lt;/strong&gt;. Below we present a mental map that shows the classification of the 56 code smells according to only this criterion.&lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_jerzyk.png&quot; alt=&quot;Jerzyk taxonomy using only obstruction criterion&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Jerzyk taxonomy according to only the obstruction criterion.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Expanse&lt;/strong&gt;: inspired by Wake’s taxonomy, this criterion talks about whether the code smell can be observed in a reduced context (within a class) or if a broader context (between several classes) needs to be considered. Possible categories are &lt;strong&gt;Within Class&lt;/strong&gt; and &lt;strong&gt;Between Classes&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Occurrence&lt;/strong&gt;: Also inspired by Wake’s taxonomy, this criterion is related to the location where (or the method by which) a code smell can be detected. Possible categories are &lt;strong&gt;Names&lt;/strong&gt;, &lt;strong&gt;Conditional Logic&lt;/strong&gt;, &lt;strong&gt;Message Calls&lt;/strong&gt;, &lt;strong&gt;Unnecessary Complexity&lt;/strong&gt;, &lt;strong&gt;Responsibility&lt;/strong&gt;, &lt;strong&gt;Interfaces&lt;/strong&gt;, &lt;strong&gt;Data&lt;/strong&gt;, &lt;strong&gt;Duplication&lt;/strong&gt; and &lt;strong&gt;Measured Smells&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The following table shows the 56 code smells in Jerzyk’s thesis classified according to the three criteria discussed above:&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_code_smells&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;table class=&quot;zebraTable&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Code Smell&lt;/th&gt;
      &lt;th&gt;Obstruction&lt;/th&gt;
      &lt;th&gt;Expanse&lt;/th&gt;
      &lt;th&gt;Occurrence&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Long Method&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Large Class&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Long Parameter List&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Primitive Obsession&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Data Clumps&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Null Check&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Oddball Solution&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Required Setup/Teardown&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Combinatorial Explosion&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Parallel Inheritance Hierarchies&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Divergent Change&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Shotgun Surgery&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Flag Argument&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Callback Hell&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dubious Abstraction&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Special Case&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Feature Envy&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Type Embedded In Name&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Indecent Exposure&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fate over Action&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Afraid to Fail&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Binary Operator in Name&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tramp Data&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hidden Dependencies&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Global Data&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Message Chain&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Message Calls&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Middle Man&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Message Calls&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Insider Trading&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Lazy Element&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Speculative Generality&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dead Code&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Duplicate Code&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;“What” Comments&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mutable Data&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Imperative Loops&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Side Effects&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Uncommunicative Name&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Magic Number&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inconsistent Names&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Boolean Blindness&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fallacious Comment&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fallacious Method Name&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Complicated Boolean Expressions&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Obscured Intent&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vertical Separation&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Complicated Regex Expression&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inconsistent Style&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Status Variable&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Clever Code&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Temporary Fields&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Conditional Complexity&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Refused Bequest&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Alternative Classes with Different Interfaces&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inappropriate Static&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Base Class Depends on Subclass&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Incomplete Library Class&lt;/td&gt;
      &lt;td&gt;Other&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Some of the names in the table are different from those that usually appear in the literature. The changes in naming were due to the introduction of more updated names, as is the case for, for instance, &lt;em&gt;Lazy Element&lt;/em&gt; or &lt;em&gt;Insider Trading&lt;/em&gt;  which were previously called &lt;em&gt;Lazy Class&lt;/em&gt; and &lt;em&gt;Inappropriate Intimacy&lt;/em&gt;, respectively.&lt;/p&gt;

&lt;p&gt;Several smells are new:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Some, like &lt;em&gt;Afraid to Fail&lt;/em&gt;, &lt;em&gt;Binary Operator in Name&lt;/em&gt;, &lt;em&gt;Clever Code&lt;/em&gt;, &lt;em&gt;Inconsistent Style&lt;/em&gt;, and &lt;em&gt;Status Variable&lt;/em&gt;, are completely new ideas.&lt;/li&gt;
  &lt;li&gt;Others are concepts that already existed in the literature but had not been considered in the context of code smells before: &lt;em&gt;Boolean Blindness&lt;/em&gt; or &lt;em&gt;Callback Hell&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Three of them propose alternatives for code smells that are being questioned in the literature: &lt;em&gt;“What” Comment&lt;/em&gt; as an alternative to &lt;em&gt;Comments&lt;/em&gt;, &lt;em&gt;Fate over Action&lt;/em&gt; as an alternative to &lt;em&gt;Data Class&lt;/em&gt;, and &lt;em&gt;Imperative Loops&lt;/em&gt; as an alternative to &lt;em&gt;Loops&lt;/em&gt; (see &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Jerzyk’s thesis&lt;/a&gt; for more on why these original code smells are debatable).&lt;/li&gt;
  &lt;li&gt;Others generalise problematic concepts that have arisen in the literature: &lt;em&gt;Complicated Regex Expression&lt;/em&gt;, &lt;em&gt;Dubious Abstraction&lt;/em&gt;, &lt;em&gt;Fallacious Comment&lt;/em&gt;, &lt;em&gt;Fallacious Method Name&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Finally, a known problem (especially in the field of functional programming), which had not been considered as a code smell until now: &lt;em&gt;Side Effects&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_code_smell_online_catalog&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One super useful and practical thing for developers in Jerzyk’s work is an &lt;a href=&quot;https://luzkan.github.io/smells/&quot;&gt;online code smells catalogue&lt;/a&gt; that, when published, included the 56 code smells in the thesis. This catalogue is an accessible and searchable website. On the date of publication of this post, the catalogue contains 56 code smells.&lt;/p&gt;

&lt;p&gt;In the catalogue code smells can be filtered by different classification criteria.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_catalog_usage_example.png&quot; alt=&quot;Example of filtering code smells in Jerzyk’s online catalogue&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Example of filtering code smells in Jerzyk’s online catalogue.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;For example, the screenshot above shows the result of filtering code smells that are &lt;em&gt;OO Abusers&lt;/em&gt; and affect &lt;em&gt;Interfaces&lt;/em&gt; which includes the &lt;em&gt;Refused Bequest&lt;/em&gt;, &lt;em&gt;Base Class depends on Subclass&lt;/em&gt;, and &lt;em&gt;Inappropriate Static&lt;/em&gt; code smells.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_in_jerzyk_catalog_example.png&quot; alt=&quot;Code smell in Jerzyk’s online catalogue&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Code smell in Jerzyk’s online catalogue.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;For each code smell, the catalogue presents the following sections: &lt;strong&gt;Smell&lt;/strong&gt; (discussion of the smell), &lt;strong&gt;Causation&lt;/strong&gt; (possible causes of the code smell), &lt;strong&gt;Problems&lt;/strong&gt; (problems that the smell can cause or design principles violates), &lt;strong&gt;Example&lt;/strong&gt; (examples of minimal code that illustrate the possible symptoms of a code smell and show a possible solution), &lt;strong&gt;Refactoring&lt;/strong&gt; (possible refactorings) and &lt;strong&gt;Sources&lt;/strong&gt; (articles or books that have described this code smell). It also includes a box containing information about possible &lt;strong&gt;aliases&lt;/strong&gt; of the code smell, the &lt;strong&gt;category&lt;/strong&gt; to which it belongs according to the criteria of &lt;strong&gt;obstruction&lt;/strong&gt;, &lt;strong&gt;occurrence&lt;/strong&gt; and &lt;strong&gt;expanse&lt;/strong&gt;, the &lt;strong&gt;related smells&lt;/strong&gt; and its relationship to them, and the &lt;strong&gt;historical origin&lt;/strong&gt; of the code smell.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;conclusions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions.&lt;/h2&gt;

&lt;p&gt;Since the code smell concept was coined in 1999, many new smells have appeared. Catalogues as flat lists of code smells catalogue are hard to remember, and don’t help to highlight the relationships that exist between different code smells.&lt;/p&gt;

&lt;p&gt;We have presented several code smells taxonomies that can help us see code smells from different points of view and relate them to each other according to different criteria: the problems they cause in the code, where they can be detected or the context that needs to be taken into account to detect them.&lt;/p&gt;

&lt;p&gt;These meaningful groupings of code smells will help us understand and remember them better than flat catalogue lists.&lt;/p&gt;

&lt;p&gt;Finally we’d like to highlight the &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;recent work by Marcel Jerzyk&lt;/a&gt; which has not only proposed new smells and created a new multi-criteria taxonomy, but also has made available to us an &lt;a href=&quot;https://luzkan.github.io/smells/&quot;&gt;online code smells catalogue&lt;/a&gt; in the form of an open-source repository and accessible and searchable website, which we believe can be very useful. useful and practical for both researchers and developers. I encourage you to take a look.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;acknowledgements&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I would like to thank my colleagues &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de La Torre&lt;/a&gt;, &lt;a href=&quot;https:/ /twitter.com/mangelviera/&quot;&gt;Miguel Viera&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/AlfredoCasado/&quot;&gt;Alfredo Casado&lt;/a&gt; for reading the final drafts of this post and giving me feedback.&lt;/p&gt;

&lt;p&gt;I’d also like to thank &lt;a href=&quot;https://www.pexels.com/es-es/@nikita-3374022/&quot;&gt;nikita&lt;/a&gt; for her photo.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;references&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;h4 id=&quot;books&quot;&gt;Books.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code 1st edition 1999&lt;/a&gt;, Martin Fowler et al.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/35135772-refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code 2nd edition 2018&lt;/a&gt;, Martin Fowler et al.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://xp123.com/articles/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;, William C. Wake&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt;, Joshua Kerievsky&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/55892270-five-lines-of-code&quot;&gt;Five Lines of Code: How and when to refactor&lt;/a&gt;, Christian Clausen&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/cs/book/show/57196550-the-programmer-s-brain&quot;&gt;The Programmer’s Brain&lt;/a&gt;, Felienne Hermans&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;papers&quot;&gt;Papers.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.researchgate.net/publication/4036832_A_Taxonomy_and_an_Initial_Empirical_Study_of_Bad_Smells_in_Code&quot;&gt;A Taxonomy and an Initial Empirical Study of Bad Smells in Code&lt;/a&gt;, Mantyla et al, 2003.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.researchgate.net/publication/220277873_Subjective_evaluation_of_software_evolvability_using_code_smells_An_empirical_study&quot;&gt;Subjective evaluation of software evolvability using code smells: An empirical study&lt;/a&gt;, Mantyla et al, 2006.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mmantyla.github.io/BadCodeSmellsTaxonomy&quot;&gt;A Taxonomy for “Bad Code Smells”
&lt;/a&gt;, Mantyla et al, 2006.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/paper.pdf&quot;&gt;Code Smells: A Comprehensive Online Catalog and Taxonomy&lt;/a&gt;, Marcel Jerzyk, 2022.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Code Smells: A Comprehensive Online Catalog and Taxonomy Msc. Thesis&lt;/a&gt;, Marcel Jerzyk, 2022.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.100.2813&amp;amp;rep=rep1&amp;amp;type=pdf&quot;&gt;Extending a Taxonomy of Bad Code Smells with
Metrics&lt;/a&gt;, R. Marticorena et al, 2006&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
Photo by &lt;a href=&quot;https://www.pexels.com/es-es/@nikita-3374022/&quot;&gt;nikita in Pexels&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2022-11-05T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/11/code-smells-taxonomies-and-catalogs-english</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/11/code-smells-taxonomies-and-catalogs-english</guid>
        </item>
      
    
      
        <item>
          <title>Eliminando código comentado</title>
          <description>&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_code&quot;&gt;Dead Code&lt;/a&gt; es un smell clasificado dentro de la taxonomía de Wake&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; en la categoría de Complejidad Innecesaria. Normalmente, suele aparecer en forma de variables, parámetros, campos, fragmentos de código, funciones o clases que no se ejecutan más.&lt;/p&gt;

&lt;p&gt;El problema es que la mayoría de las veces no estamos seguros de si un determinado elemento del código ya no se usa o no. No saber si un código se ejecuta o no, hace que aumente la carga cognitiva (tenemos que tenerlo en cuenta y comprenderlo) a la hora de hacer cambios de funcionalidad o corregir bugs, lo cual aumenta la complejidad del cambio de forma totalmente innecesaria. Para hacer desaparecer esta complejidad bastaría con eliminar el código muerto, pero para ello primero debemos ser capaces de detectarlo.&lt;/p&gt;

&lt;p&gt;Hay diversas maneras de detectar el código muerto. Las más efectivas se apoyan en el uso de herramientas, por ejemplo, la mayoría de IDEs advierten sobre elementos que ya no se usan. Estas herramientas reducen el coste que supondría tener que detectar el código muerto mediante sólo la lectura del código.&lt;/p&gt;

&lt;p&gt;Las herramientas disponibles dependen tanto del lenguaje que se usa como de las características del lenguaje que se usen en el código. En general podemos decir que la detección de código muerto será más difícil entre más dinámicas sean las características que estemos utilizando.&lt;/p&gt;

&lt;p&gt;En este post nos centraremos en un tipo de código muerto que es quizás el más fácil de detectar: el código comentado.&lt;/p&gt;

&lt;h2 id=&quot;problemas-del-código-comentado&quot;&gt;Problemas del código comentado.&lt;/h2&gt;
&lt;p&gt;Con frecuencia, solemos encontrar el código comentado intercalado con el resto del código. Esto provoca una ruptura del flujo de lectura que nos obliga a hacer un esfuerzo para ignorar el código comentado. Si los bloques de código comentados son grandes, en ocasiones nos vemos obligados a usar el scroll para continuar la lectura.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/large-comment-block.png&quot; alt=&quot;Bloque largo de código comentado&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Bloque largo de código comentado.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Además del aumento de la carga cognitiva que genera todo código muerto, el código comentado puede generar confusión cuando uno lo tiene en cuenta, ya sea con la intención de usarlo en el futuro, o como ayuda para entender el código actual, debido a que suele quedar rápidamente desfasado.&lt;/p&gt;

&lt;p&gt;Eliminar el código comentado suele ser sencillo, simplemente borramos el comentario que contiene el código y si al eliminarlo, el fichero que lo contenía queda vacío, lo eliminamos también.&lt;/p&gt;

&lt;h2 id=&quot;resistencias-frecuentes-a-eliminar-el-código-comentado&quot;&gt;Resistencias frecuentes a eliminar el código comentado.&lt;/h2&gt;
&lt;p&gt;Uno de los argumentos que nos solemos encontrar para no querer eliminar código comentado es que se piensa que se necesitará en algún momento del futuro. Por ejemplo, a veces se quiere guardar el código de una implementación anterior, que es compleja de recordar.&lt;/p&gt;

&lt;p&gt;Una manera más práctica de hacer posible la recuperación de una versión anterior del código sin necesidad de mantener código comentado, es confiar en el &lt;a href=&quot;https://en.wikipedia.org/wiki/Version_control&quot;&gt;sistema de control de versiones&lt;/a&gt; con el que trabajamos.&lt;/p&gt;

&lt;p&gt;Un argumento frecuente en contra de esta última solución es que es mucho más fácil recuperar código comentado que encontrar una versión anterior en el control de versiones.&lt;/p&gt;

&lt;p&gt;Aunque es verdad que es más difícil encontrar la versión anterior en el control de versiones, esta fricción se reduce si mejora nuestra habilidad para navegar en el histórico del control de versiones (ya sea a través del IDE o mediante la línea de comandos). Además, debemos tener en cuenta dos factores en contra de mantener el código comentado:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Con el tiempo la necesidad de recuperar el código de una versión anterior se vuelve cada vez menos probable porque el código va a divergir cada vez más de esa versión pasada.&lt;/li&gt;
  &lt;li&gt;El problema de complejidad innecesaria que hará más caro evolucionar el código hasta que eliminemos el código comentado.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;eliminando-código-comentado-de-forma-automática&quot;&gt;Eliminando código comentado de forma automática.&lt;/h2&gt;
&lt;p&gt;Si comentar código ha sido una práctica muy utilizada por un equipo durante un tiempo largo, se puede llegar a una situación en la que el coste de eliminarlo sea elevado, y no nos quedará otro remedio que convivir con él durante mucho tiempo, mientras vamos alternando la entrega de funcionalidad con borrar código comentado de forma oportunista&lt;/p&gt;

&lt;p&gt;En una situación así puede ser interesante explorar herramientas que borren código comentado de manera automática. Existen múltiples herramientas que podrían hacer este trabajo en la mayoría de los lenguajes. Una manera de acotar la exploración de herramientas es empezar por conocer nuestro IDE y sacarle provecho.&lt;/p&gt;

&lt;p&gt;Por ejemplo, recientemente hemos aplicado esta estrategia de eliminación automática de código comentado en un cliente que trabajaba con Java e Intellij.&lt;/p&gt;

&lt;p&gt;Intellij dispone de una herramienta de análisis de código que cuenta con diferentes tipos de inspecciones. Aparte del análisis en sí, lo más potente de esta herramienta es que permite ejecutar acciones (“fixes”) sobre los problemas detectados.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/run-inspection-menu.png&quot; alt=&quot;Ejecución de las inspecciones por nombre en IntelliJ&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Ejecución de las inspecciones por nombre en IntelliJ.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;La inspección concreta para detectar código comentado es &lt;strong&gt;commented out code&lt;/strong&gt;. Se puede seleccionar el scope del análisis, diversos filtros y el número de líneas mínimas de los comentarios a considerar (lo que puede ser útil si, por ejemplo, queremos empezar por grandes bloques de código comentado).&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/run-commented-out.png&quot; alt=&quot;Opciones para ejecutar la inspección commented out code&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Opciones para ejecutar la inspección &apos;commented out code&apos;.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;A continuación, podemos seleccionar los elementos detectados que queramos y proceder a realizar algunos de los fixes que el IDE nos proponga, en este caso aplicaremos &lt;strong&gt;Delete comment&lt;/strong&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-10-18-eliminando-codigo-comentado/delete-comments.png&quot; alt=&quot;Fixes propuestos para resolver el commented out code&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Fixes propuestos para resolver los caso de &apos;commented out code&apos;.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Tras realizar estos cambios, ejecuta tus test para ver que no se ha modificado el comportamiento esperado. Dependiendo de tu situación (cobertura de tests, confianza del equipo, etc.) podría ser interesante verificar también que el borrado se ha hecho correctamente leyendo el código resultante. Sin embargo, si hay muchos cambios que verificar esto puede ser muy laborioso. Lo que podrías hacer en ese caso es planificar el borrado en varias fases, dividiéndolo por tipos de fichero, por paquetes, o por otro criterio de división que se adecue a tu situación.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión.&lt;/h2&gt;
&lt;p&gt;Hemos visto que el código comentado es una de las formas en la que se presenta el &lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_code&quot;&gt;Dead Code&lt;/a&gt; smell, y como este smell aumenta de forma innecesaria la complejidad de nuestro código. Hemos presentado los argumentos más comunes (en nuestra experiencia) para resistirse a eliminar el código comentado, y hemos dado argumentos para rebatirlos. Finalmente, cuando trabajas con una base de código plagado de código comentado, hemos recomendado una alternativa a su eliminación mediante refactorings oportunistas, que consiste en explorar las herramientas que tienes a mano (tu IDE) para ver si disponen de funcionalidades para eliminar código muerto de manera automática. Esto te permitirá eliminar una mayor cantidad de código comentado con un coste asumible.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas&lt;/h2&gt;
&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Puedes leer sobre esta taxonomía y otras más en nuestro post &lt;a href=&quot;https://codesai.com/posts/2022/09/code-smells-taxonomies-and-catalogs&quot;&gt;De taxonomías y catálogos de code smells&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2022-10-18T09:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/10/eliminando-codigo-comentado</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/10/eliminando-codigo-comentado</guid>
        </item>
      
    
      
        <item>
          <title>&quot;Split or condition in if&quot; refactoring</title>
          <description>&lt;p&gt;We’d like to document a refactoring that we usually teach to teams we work with: the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring.&lt;/p&gt;

&lt;h2&gt;Split or condition in if.&lt;/h2&gt;

&lt;h3&gt;Motivation.&lt;/h3&gt;

&lt;p&gt;Sometimes we have nested conditionals that are branching depending on the same information. When an outer if condition contains an &lt;strong&gt;or&lt;/strong&gt; which combines boolean expressions that check that information, splitting the &lt;strong&gt;or&lt;/strong&gt; in the outer if may lead to opportunities to remove the rechecks in inner branching. This happens because having that &lt;strong&gt;or&lt;/strong&gt; in the outer if forces us to check again the same information in an inner if condition.&lt;/p&gt;

&lt;p&gt;Let’s see an example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f4f5da2620d88d281e46538b4c9ba3c0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Have a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execute&lt;/code&gt; method code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rover&lt;/code&gt; class (we’ve omitted some code for brevity). Notice how this code is branching twice depending on the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command&lt;/code&gt; variable. Using an &lt;strong&gt;or&lt;/strong&gt; in the condition of the outer if, makes it necessary to recheck the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command&lt;/code&gt; variable again in inner if conditions. This adds unnecessary nesting and duplication that can be easily removed if we first split the &lt;strong&gt;or&lt;/strong&gt; in the outer if.&lt;/p&gt;

&lt;h3&gt;Mechanics.&lt;/h3&gt;

&lt;p&gt;Some IDEs have automated this refactoring, for instance, the &lt;a href=&quot;https://www.jetbrains.com/&quot;&gt;JetBrains&lt;/a&gt; family of IDEs. 
If you’re using one of JetBrains IDEs, you only need to place your cursor on the &lt;strong&gt;or&lt;/strong&gt; condition and press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ALT+ENTER&lt;/code&gt; to ask the IDE for possible context sensitive actions and select the &lt;strong&gt;Split ‘||’ condition in ‘if’&lt;/strong&gt; from the pop up menu.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/split_or_condition_in_if.png&quot; alt=&quot;Automated refactoring in WebStorm&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Automated refactoring in WebStorm.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If your IDE does not have this refactoring automated, you can use the following mechanics to safely split the &lt;strong&gt;or&lt;/strong&gt; condition in the if:&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;mechanics&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;
       Duplicate the if. &lt;br /&gt;
       This step might be different depending on if there was initially an else or not. 
       &lt;ul&gt;
           &lt;li&gt;If there was an else, you’d need to add the duplicated code in an else if block.&lt;/li&gt;
           &lt;li&gt;If there was no else, you can just duplicate the whole if besides the original one. &lt;/li&gt;
       &lt;/ul&gt;
       Note that this step may change the behaviour. The tests may not pass until you do the next step.
       &lt;/li&gt;
    &lt;li&gt;
    Remove one clause of the &lt;b&gt;or&lt;/b&gt; condition from one of the copies and the other clause of the or condition from the other copy. &lt;br /&gt;
    At this point, run the tests to be sure that you haven’t accidentally modified the behaviour and the refactoring went ok.
    &lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/split_or_condition_in_if_without_else.png&quot; alt=&quot;Refactoring mechanics when there’s no else.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Refactoring mechanics when there’s no else.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/split_or_condition_in_if_with_else.png&quot; alt=&quot;Refactoring mechanics when there’s an else.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Refactoring mechanics when there’s an else.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3&gt;Related code smells.&lt;/h3&gt;
&lt;p&gt;Mainly &lt;em&gt;Duplicated Code&lt;/em&gt; and &lt;em&gt;Complicated Boolean Expression&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Splitting or condition in if&lt;/strong&gt; results in a code where is easier to remove both &lt;em&gt;Duplicated Code&lt;/em&gt; and &lt;em&gt;Complicated Boolean Expression&lt;/em&gt; smells, which in turn may unmask other smells.&lt;/p&gt;

&lt;p&gt;In the following video, we show how after applying this refactoring we can easily remove duplicated if conditions because they become obsolete (even though the refactoring is automated in WebStorm, we used the mechanics described above for demonstration purposes).&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;Y3VQ5COBXgU&quot;&gt;
    &lt;div data-id=&quot;Y3VQ5COBXgU&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/Y3VQ5COBXgU/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;h3&gt;Related refactorings.&lt;/h3&gt;

&lt;p&gt;The inverse of this refactoring pattern is the &lt;strong&gt;Combine ifs&lt;/strong&gt; refactoring pattern described by &lt;a href=&quot;https://twitter.com/thedrlambda&quot;&gt;Christian Clausen&lt;/a&gt; in his book &lt;a href=&quot;https://www.manning.com/books/five-lines-of-code&quot;&gt;Five Lines of Code, How and when to refactor&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We have described the &lt;strong&gt;Split or condition in if&lt;/strong&gt; refactoring, and provided safe mechanics to perform it when it’s not automated by your IDE. We hope this refactoring technique might be useful to you.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/rubendm23&quot;&gt;Rubén Díaz&lt;/a&gt; for giving me feedback on the final draft of this post.&lt;/p&gt;

&lt;h4&gt;Update 2025/05/20:&lt;/h4&gt;

&lt;p&gt;I’ve just discovered that &lt;a href=&quot;https://xp123.com/about/&quot;&gt;William Wake&lt;/a&gt; had already documented this refactor in 2020 with the name &lt;strong&gt;Duplicate and Customize&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Have a look at his great post: &lt;a href=&quot;https://xp123.com/refactor-duplicate-and-customize/&quot;&gt;Refactor: Duplicate and Customize&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was applying this refactor before 2017 (it was recorded in the YouTube video &lt;a href=&quot;https://www.youtube.com/watch?v=lBUmAZuXVmo&quot;&gt;Expressing symmetry in Mars Rover movement refactoring&lt;/a&gt; from 2017), but didn’t document it until five years later.&lt;/p&gt;

&lt;p&gt;The first time I applied it was while solving the Gilded Rose kata (which is coincidentally the same example that Wake shows to demonstrate the refactor in his post).
I was just trying to simplify the same conditional in small steps and this was the way I found best. I’m a big fan of Wake’s work, so it’s great for me that we independently got to the same refactor.&lt;/p&gt;

</description>
          <pubDate>2022-10-08T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/10/split-or-condition</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/10/split-or-condition</guid>
        </item>
      
    
      
        <item>
          <title>Simplifying jest stubs using jest-when</title>
          <description>&lt;p&gt;In a recent deliberate practice session with some developers from &lt;a href=&quot;https://audiense.com/&quot;&gt;Audiense&lt;/a&gt; (with whom we’re doing the &lt;a href=&quot;https://github.com/Codesai/practice_program_js&quot;&gt;Codesai’s Practice Program&lt;/a&gt; twice a month), we were solving the &lt;a href=&quot;https://kata-log.rocks/unusual-spending-kata&quot;&gt;Unusual Spending Kata
&lt;/a&gt; in JavaScript.&lt;/p&gt;

&lt;p&gt;While test-driving the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UnusualSpendingDetector&lt;/code&gt; class we found that writing &lt;a href=&quot;http://xunitpatterns.com/Test%20Stub.html&quot;&gt;stubs&lt;/a&gt; using plain &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt; can be a bit hard. The reason is that &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt; does not match mocked function arguments, so to create stubbed responses for particular values of the arguments we are forced to introduce logic in the tests.&lt;/p&gt;

&lt;p&gt;Have a look at a fragment of the tests we wrote for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UnusualSpendingDetector&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8c7d993522532cc5f266cfb63f6808f2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paymentsRepositoryWillReturn&lt;/code&gt; helper function, we extracted it to remove duplication in the tests. In this function we had to add explicit checks to see whether the arguments of a call match some given values. It reads more or less ok, but we were not happy with the result because we were adding logic in test code (see &lt;a href=&quot;https://gist.github.com/trikitrok/1e4fb27cc6acf16acc1cffd5d97a69de&quot;&gt;all the test cases&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Creating these stubs can be greatly simplified using a library called &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt; which helps to write stubs for specifically matched mocked function arguments. Have a look at the same fragment of the tests we wrote for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UnusualSpendingDetector&lt;/code&gt; class now using &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt;:
&lt;script src=&quot;https://gist.github.com/trikitrok/41c2a689534d317185e3728c377e190e.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Notice how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paymentsRepositoryWillReturn&lt;/code&gt; helper function is not needed anymore, and how the fluent interface of &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt; feels nearly like canonical &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt; syntax.&lt;/p&gt;

&lt;p&gt;We think that using &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt; is less error prone than having to add logic to write your own stubs with plain &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt;, and it’s as readable as or more than using only &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt; (see &lt;a href=&quot;https://gist.github.com/trikitrok/d26432d888aef427016d8bc5fed58ab3&quot;&gt;all the refactored test cases&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To improve readability we played a bit with a functional builder. This is the same fragment of the tests we wrote for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UnusualSpendingDetector&lt;/code&gt; class now using a functional builder over &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d029e642b5d7d7fd22e506a649a88601.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PaymentsRepositoryHelper&lt;/code&gt; is as follows:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d6a9fdeca0d482c86e051544b5f5d501.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In this last version we were just playing a bit with the code in order to find a way to configure the stubs both in terms of the domain and without &lt;a href=&quot;https://en.wikipedia.org/wiki/Free_variables_and_bound_variables&quot;&gt;free variables&lt;/a&gt; (have a look at &lt;a href=&quot;https://gist.github.com/trikitrok/6ae7a113b0c1651445bb75dd867938fe&quot;&gt;all the test cases using this builder&lt;/a&gt;). In any case, we think that the previous version using &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt; was already good enough.&lt;/p&gt;

&lt;p&gt;Probably you already knew &lt;a href=&quot;https://www.npmjs.com/package/jest-when&quot;&gt;jest-when&lt;/a&gt;, if not, give it a try. We think it can help you to write simpler stubs if you’re using &lt;a href=&quot;https://jestjs.io/&quot;&gt;jest&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2022-09-29T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/09/jest-when-stubs</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/09/jest-when-stubs</guid>
        </item>
      
    
      
        <item>
          <title>De taxonomías y catálogos de code smells</title>
          <description>&lt;p&gt;&lt;strong&gt;Índice.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introducción: refactoring y code smells.&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#martin_fowler_catalog&quot;&gt;Martin Fowler, Code Smells y Catálogos.&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#taxonomies&quot;&gt;Taxonomías&lt;/a&gt;&lt;/li&gt;
    &lt;ol&gt;
        &lt;li&gt;&lt;a href=&quot;#wake_taxonomy&quot;&gt;Taxonomías de Wake 2003&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#mantyla_taxonomy_2003&quot;&gt;Taxonomía de Mäntylä et al 2003&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#mantyla_taxonomy_2006&quot;&gt;Taxonomía de Mäntylä et al 2006&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;#jerzyk_taxonomy_2022&quot;&gt;Taxonomía de Jerzyk et al 2022&lt;/a&gt;&lt;/li&gt;
        &lt;ol&gt;
            &lt;li&gt;&lt;a href=&quot;#jerzyk_code_smells&quot;&gt;Catálogo de Code Smells&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;#jerzyk_code_smell_online_catalog&quot;&gt;Catálogo online.&lt;/a&gt;&lt;/li&gt;
        &lt;/ol&gt;
    &lt;/ol&gt;
    &lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;Conclusiones.&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#greetings&quot;&gt;Agradecimientos.&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#references&quot;&gt;Referencias.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a name=&quot;introduction&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt; Introducción: refactoring y code smells.&lt;/h2&gt;

&lt;p&gt;Refactorizar es una práctica que nos permite evolucionar un código de forma sostenible. Para poder hacerlo necesitamos, en primer lugar, ser capaces de reconocer el código problemático que necesita ser refactorizado.&lt;/p&gt;

&lt;p&gt;Los code smells son descripciones de señales o síntomas que nos avisan de posibles problemas de diseño en nuestro código. Detectar estos problemas y eliminarlos tan pronto como uno se da cuenta de que hay algo mal es crucial.&lt;/p&gt;

&lt;p&gt;El refactoring produce mejores resultados y es más barato si se hace con regularidad. Entre más tiempo permanezca sin refactorizar un código problemático, más se agravará su efecto y constreñirá  el futuro desarrollo del código, contribuyendo directamente a la deuda técnica. Esta situación hará el código cada vez más difícil de mantener, lo que tendrá un impacto económico muy negativo, pudiendo incluso llegar, en el peor de los casos, a ser tan complicada que ya no se pueda seguir manteniendo el código.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_feature_cost_vs_time.png&quot; alt=&quot;Coste de introducir una feature en función del tiempo&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Coste de introducir una feature en función del tiempo (imagen de The Three Values of Software de J. B. Rainsberger).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Otra consecuencia, a veces, no tan visible de la mala calidad del código es su efecto en los desarrolladores. Menos refactor, lleva a código menos mantenible, que nos lleva a tardar más tiempo en implementar nuevas funcionalidades, lo cuál nos mete más presión de tiempo, lo que nos lleva a testear menos, lo que nos lleva a refactorizar menos… Es un círculo vicioso que puede tener un efecto muy desmoralizador.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_vicious_cycle.png&quot; alt=&quot;Círculo vicioso sin refactor&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Círculo vicioso sin refactor.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Por tanto, entender y saber identificar los code smells nos da mucho poder porque seremos capaces de detectar problemas de diseño cuando aún son pequeños y están muy localizados en zonas concretas de nuestro código, y eso tendrá un efecto económico y anímico muy positivo.&lt;/p&gt;

&lt;p&gt;El problema es que los code smells no se suelen entender demasiado bien. Esto es entendible porque sus definiciones son a veces abstractas, difusas y abiertas a interpretación. Algunos code smells parecen obvios, otros no tanto, y algunos pueden enmascarar a otros code smells.&lt;/p&gt;

&lt;p&gt;Además, recordemos que los code smells son sólo síntomas de posibles problemas, y no garantías de problemas. Para complicarlo aún más, además de los posibles falsos positivos, existen grados en el problema que cada smell representa, trade-offs entre smells y contraindicaciones en sus refactorings (en ocasiones “el remedio puede ser peor que la enfermedad”).&lt;/p&gt;

&lt;p&gt;Por tanto, reconocer los code smells que señalan problemas de diseño, es decir, que no son falsos positivos, es una habilidad sutil, que requiere de experiencia y juicio. Adquirir esta habilidad, que a veces parece una especie de sentido arácnido, puede llevar tiempo.&lt;/p&gt;

&lt;p&gt;En nuestra experiencia enseñando y acompañando a muchos equipos identificar code smells es una de las mayores barreras iniciales al refactoring. Muchos desarrolladores no se dan cuenta de los problemas del código que están generando cuando aún son pequeños. Lo que solemos ver es que no se dan cuenta hasta que los problemas son bastante grandes y/o se han combinado con otros problemas, propagándose por su base de código.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;martin_fowler_catalog&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;catálogos-de-code-smells&quot;&gt;Catálogos de code smells.&lt;/h2&gt;

&lt;p&gt;En 1999 Fowler y Beck publicaron un catálogo de code smells en un capítulo del libro, 
&lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;. Este catálogo contiene las descripciones de 22 code smells.&lt;/p&gt;

&lt;p&gt;En 2018 Fowler publicó una &lt;a href=&quot;https://www.goodreads.com/book/show/35135772-refactoring&quot;&gt;segunda edición de su libro&lt;/a&gt;. En esta nueva edición hay una serie de cambios con respecto a la primera, principalmente en el catálogo de smells y el catálogo de refactorings (que detalla en &lt;a href=&quot;https://martinfowler.com/articles/refactoring-2nd-changes.html&quot;&gt;Changes for the 2nd Edition of Refactoring&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Si nos centramos en los smells, lo que nos interesa en este post, los cambios son los siguientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Introduce cuatro code smells nuevos: &lt;em&gt;Mysterious Name&lt;/em&gt;, &lt;em&gt;Global Data&lt;/em&gt;, &lt;em&gt;Mutable Data&lt;/em&gt; y &lt;em&gt;Loops&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Elimina dos smells: &lt;em&gt;Parallel Inheritance Hierarchies&lt;/em&gt; y &lt;em&gt;Incomplete Library Class&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Renombra cuatro smells: &lt;em&gt;Lazy Class&lt;/em&gt; pasa a ser &lt;em&gt;Lazy Element&lt;/em&gt;, &lt;em&gt;Long Method&lt;/em&gt; pasa a ser &lt;em&gt;Long Function&lt;/em&gt;, &lt;em&gt;Inappropriate Intimacy&lt;/em&gt; pasa a ser &lt;em&gt;Insider Trading&lt;/em&gt; y &lt;em&gt;Switch Statement&lt;/em&gt; pasa a ser &lt;em&gt;Repeated Switches&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quedan un total de 24 code smells, que aunque suelen tener nombres llamativos y memorables, son difíciles de recordar.&lt;/p&gt;

&lt;p&gt;¿De qué manera podríamos entender mejor los code smells? ¿Cómo podríamos recordarlos más fácilmente?&lt;/p&gt;

&lt;p&gt;En este post, y algunos posteriores, hablaremos de estrategias para profundizar, recordar y entender mejor los code smells.&lt;/p&gt;

&lt;h2 id=&quot;estrategias-organizativas&quot;&gt;Estrategias organizativas.&lt;/h2&gt;

&lt;p&gt;Organizar y manipular la información, verla desde diferentes puntos de vista, nos puede ayudar a entender y recordar mejor. Las taxonomías son un tipo de estrategia organizativa, que nos permite agrupar un material de estudio según su significado, creando agrupamientos significativos de información (“&lt;em&gt;chunks&lt;/em&gt;”), que facilitarán el aprendizaje.&lt;/p&gt;

&lt;p&gt;Como comentamos el catálogo de Fowler de 2018 es una lista plana que no proporciona ningún tipo de clasificación. Si bien, leyendo las descripciones de los de code smells, y las secciones de motivación de los diferentes refactorings podemos vislumbrar que algunos smells están más relacionados entre ellos que con otros smells, estas relaciones no se expresan de forma explícita y quedan difuminadas y dispersas en diferentes partes del libro.&lt;/p&gt;

&lt;p&gt;El uso de taxonomías que clasifican code smells similares puede ser beneficioso para entenderlos mejor, recordarlos y reconocer las relaciones que existen entre ellos.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;taxonomies&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;taxonomías&quot;&gt;Taxonomías.&lt;/h2&gt;

&lt;p&gt;Ha habido diferentes intentos de clasificar los code smells agrupándolos según diferentes criterios. La clasificación más popular es la de Mäntylä et al 2006 pero no es la primera. A continuación mostraremos algunas que consideramos bastante interesantes.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;wake_taxonomy&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;wake-2003&quot;&gt;Wake 2003.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://xp123.com/articles/&quot;&gt;Wake&lt;/a&gt; en su libro &lt;a href=&quot;https://xp123.com/articles/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt; de 2003 describe 9 nuevos code smells que no aparecían en el catálogo original de Fowler: &lt;em&gt;Dead Code&lt;/em&gt;, &lt;em&gt;Null Check&lt;/em&gt;, &lt;em&gt;Special Case&lt;/em&gt;, &lt;em&gt;Magic Number&lt;/em&gt;, &lt;em&gt;Combinatorial Explosion&lt;/em&gt;, &lt;em&gt;Complicated Boolean Expression&lt;/em&gt;, y tres relacionados con malos nombres: &lt;em&gt;Type Embedded in Name&lt;/em&gt;, &lt;em&gt;Uncommunicative Names&lt;/em&gt; e &lt;em&gt;Inconsistent Names&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Wake clasifica explícitamente los code smells dividiéndolos primero en dos categorías amplias, &lt;em&gt;Smells within Classes&lt;/em&gt; y &lt;em&gt;Smells Between Classes&lt;/em&gt;, dependiendo, respectivamente, de si el code smell puede ser observado desde una clase o si se necesita considerar un contexto más amplio (varias clases). Cada una de estas categorías se divide en subcategorías que agrupan los code smells según en dónde se pueden detectar. Este criterio de clasificación, denominado más tarde &lt;em&gt;“occurrence”&lt;/em&gt; por Jerzyk, responde a la pregunta: “¿dónde aparece este code smell?”.&lt;/p&gt;

&lt;p&gt;Siguiendo este criterio Wake encuentra las siguientes 10 subcategorías.&lt;/p&gt;

&lt;p&gt;Dentro de la categoría de &lt;em&gt;Smells within Classes&lt;/em&gt; estarían las siguientes subcategorías:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Measured Smells&lt;/strong&gt;: code smells que pueden ser identificados fácilmente con simples métricas de longitud.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Names&lt;/strong&gt;: code smells que crean confusión semántica y afectan a nuestra capacidad de crear modelos mentales que nos ayuden a comprender, recordar y razonar sobre el código.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unnecessary Complexity&lt;/strong&gt;: code smells relacionados con código innecesario que añade carga mental y complejidad. Código muerto, violaciones de &lt;a href=&quot;https://martinfowler.com/bliki/Yagni.html&quot;&gt;YAGNI&lt;/a&gt; y complejidad accidental.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Duplication&lt;/strong&gt;: la némesis de los desarrolladores. Estos code smells provocan que haya mucho más código que mantener (carga cognitiva y física), aumentan la propensión a errores y dificultan la comprensión del código.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Conditional Logic Smells&lt;/strong&gt;: code smells que complican la lógica condicional haciendo difícil razonar sobre ella, dificultando el cambio y aumentando la propensión a cometer errores. Algunos de ellos son sucedáneos de mecanismos de la orientación a objetos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Las subcategorías dentro de la categoría de &lt;strong&gt;Smells between Classes&lt;/strong&gt; son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Data&lt;/strong&gt;: code smells en los que encontramos, o bien pseudo objetos (estructuras de datos sin comportamiento), o bien encontramos que falta alguna abstracción.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;: code smells relacionados con un mal uso de la herencia.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Responsibility&lt;/strong&gt;: code smells relacionados con una mala asignación de responsabilidades.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Accommodating Change&lt;/strong&gt;: code smells que se manifiestan cuando nos encontramos con mucha fricción al introducir cambios. Suelen estar provocados por combinaciones de otros code smells.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Library Classes&lt;/strong&gt;: code smells relacionados con el uso de librerías de terceros.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_wake_map.png&quot; alt=&quot;Taxonomía de Wake 2003&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Taxonomía de Wake (los nuevos smells aparecen en verde).&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Wake presenta cada smell siguiendo un formato estándar con las siguientes secciones: &lt;strong&gt;Smell&lt;/strong&gt; (el nombre y aliases), &lt;strong&gt;Síntomas&lt;/strong&gt; (pistas que pueden ayudar a detectarlo), &lt;strong&gt;Causas&lt;/strong&gt; (notas sobre cómo puede haberse generado), &lt;strong&gt;Qué Hacer&lt;/strong&gt; (posibles refactorings), &lt;strong&gt;Beneficios&lt;/strong&gt; (cómo mejorará el código al eliminarlo) y &lt;strong&gt;Contraindicaciones&lt;/strong&gt; (falsos positivos y trade-offs). En algunos casos añade notas relacionando el code smell con principios de diseño que podrían ayudar a evitarlo.&lt;/p&gt;

&lt;p&gt;El libro además contiene muchos ejercicios prácticos y tablas muy útiles (síntomas vs code smells, smells vs refactorings, refactorings inversos, etc) y ejercicios que relacionan los code smells con otros conceptos como principios de diseño o patrones de diseño.&lt;/p&gt;

&lt;p&gt;Es un libro muy recomendable para profundizar en la disciplina de refactoring y entender mejor cuándo y por qué aplicar los refactorings que aparecen en el catálogo de Fowler.&lt;/p&gt;

&lt;p&gt;Lo que enseñamos sobre code smells en nuestro curso sobre &lt;a href=&quot;https://codesai.com/cursos/refactoring/&quot;&gt;Code Smells &amp;amp; Refactoring&lt;/a&gt; se basa principalmente en esta clasificación de Wake aderezada con un poco de nuestra experiencia, aunque también hacemos referencia al resto de taxonomías de las que hablamos en este post.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;mantyla_taxonomy_2003&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mäntylä-et-al-2003&quot;&gt;Mäntylä et al 2003.&lt;/h3&gt;

&lt;p&gt;En ella los code smells se agrupan según el efecto que tienen en el código (el tipo de problema, lo que hacen difícil o las prácticas o principios que rompen). Jerzyk 2022 denomina “&lt;em&gt;obstrucción&lt;/em&gt;” a este criterio de clasificación.&lt;/p&gt;

&lt;p&gt;En la clasificación original de 2003 (&lt;a href=&quot;https://www.researchgate.net/publication/4036832_A_Taxonomy_and_an_Initial_Empirical_Study_of_Bad_Smells_in_Code&quot;&gt;A Taxonomy and an Initial Empirical Study of Bad Smells in Code&lt;/a&gt;) había 7 categorías de code smells: &lt;em&gt;Bloaters&lt;/em&gt;, &lt;em&gt;Object-Orientation Abusers&lt;/em&gt;, &lt;em&gt;Change Preventers&lt;/em&gt;, &lt;em&gt;Dispensables&lt;/em&gt;, &lt;em&gt;Encapsulators&lt;/em&gt;, &lt;em&gt;Couplers&lt;/em&gt; y &lt;em&gt;Others&lt;/em&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_mantyla_2003.png&quot; alt=&quot;Taxonomía de Mäntylä et al 2003&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Taxonomía de Mäntylä et al 2003.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Así es como definen cada una de las categorías (disculpen al traductor…):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Bloaters&lt;/strong&gt;: “representan algo en el código que ha crecido tanto que ya no se puede manejar de forma efectiva.“&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Object-Orientation Abusers&lt;/strong&gt;: “esta categoría de smells se relaciona con casos en los que la solución no explota completamente las posibilidades del diseño orientado a objetos.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Change Preventers&lt;/strong&gt;: “esta categoría hace referencia a estructuras de código que dificultan considerablemente cambiar el software.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dispensables&lt;/strong&gt;: “estos smells representan algo innecesario que debería ser eliminado del código.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Encapsulators&lt;/strong&gt;: “tiene que ver con mecanismos de comunicación o encapsulación de datos.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Couplers&lt;/strong&gt;: “estos smells representan casos de acoplamiento alto, lo cual va en contra de los principios de diseño orientado a objetos”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Others&lt;/strong&gt;: “esta categoría contiene los code smells restantes (&lt;em&gt;Comments&lt;/em&gt; e &lt;em&gt;Incomplete Library Class&lt;/em&gt;) que no encajaban en ninguna de las categorías anteriores.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el artículo, Mäntylä et al discuten los motivos por los que incluyeron cada smell en una determinada categoría y no otra, aunque admiten que algunos de ellos podrían ser clasificados en más de una categoría.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;mantyla_taxonomy_2006&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mäntylä-et-al-2006&quot;&gt;Mäntylä et al 2006.&lt;/h3&gt;

&lt;p&gt;En 2006 Mäntylä et al sacaron otro artículo (&lt;a href=&quot;https://scholar.google.es/citations?view_op=view_citation&amp;amp;hl=es&amp;amp;user=rQHJ67UAAAAJ&amp;amp;citation_for_view=rQHJ67UAAAAJ:IjCSPb-OGe4C&quot;&gt;Subjective evaluation of software evolvability using code smells: An empirical study&lt;/a&gt;) en el que revisaron su clasificación original de 2003.&lt;/p&gt;

&lt;p&gt;La diferencia de esta nueva versión es que elimina las categorías &lt;strong&gt;Encapsulators&lt;/strong&gt; (moviendo los smells &lt;em&gt;Message Chains&lt;/em&gt; y &lt;em&gt;Middle Man&lt;/em&gt; a la categoría &lt;strong&gt;Couplers&lt;/strong&gt;) y &lt;strong&gt;Others&lt;/strong&gt; (&lt;em&gt;Comments&lt;/em&gt; e &lt;em&gt;Incomplete Library Class&lt;/em&gt; desaparecen de la taxonomía), y mueve el code smell &lt;em&gt;Parallel Inheritance Hierarchies&lt;/em&gt; de la categoría de &lt;strong&gt;Object-Orientation Abusers&lt;/strong&gt; a la categoría de &lt;strong&gt;Change Preventers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esta última versión de su taxonomía es la que se ha hecho más popular en internet (se puede encontrar en muchas webs, cursos y posts), probablemente debido a la mayor accesibilidad (facilidad de lectura) del resumen del artículo que aparece en la web que resume el artículo: &lt;a href=&quot;https://mmantyla.github.io/BadCodeSmellsTaxonomy&quot;&gt;A Taxonomy for “Bad Code Smells”&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_mantyla_2006.jpg&quot; alt=&quot;Taxonomía de Mäntylä et al 2006&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Taxonomía de Mäntylä et al 2006.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Lo interesante no es tanto la discusión de en qué categoría debe caer cada smell, sino el empezar a pensar qué un determinado smell puede tener diferentes tipos de efectos en el código y las relaciones entre estos efectos. De hecho, en posteriores clasificaciones desde el punto de vista del efecto de un smell en el código, no consideran ya las categorías como excluyentes, sino que, un mismo smell puede caer en varias categorías, ya que consideran que es más útil no perder la información de que un smell puede producir varios efectos.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_taxonomy_2022&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;jerzyk-et-al-2022&quot;&gt;Jerzyk et al 2022.&lt;/h3&gt;

&lt;p&gt;En 2022 Marcel Jerzyk publicó su tesis de master, &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Code Smells: A Comprehensive Online
Catalog and Taxonomy&lt;/a&gt; y un &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/paper.pdf&quot;&gt;artículo con el mismo título&lt;/a&gt;. Su investigación sobre code smells tenía tres objetivos:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Proporcionar un catálogo público que pudiera ser útil como una base de conocimiento unificada tanto para investigadores como para desarrolladores.&lt;/li&gt;
  &lt;li&gt;Identificar todos los conceptos posibles que están siendo caracterizados como code smells y determinar posibles controversias sobre ellos.&lt;/li&gt;
  &lt;li&gt;Asignar propiedades apropiadas a los code smells con el fin de caracterizarlos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para conseguir estos objetivos realizaron una revisión de la literatura existente hasta ese momento sobre code smells, haciendo especial énfasis en las taxonomías de code smells.&lt;/p&gt;

&lt;p&gt;En su tesis identifican y describen 56 code smells, de los cuales 16 son propuestas originales suyas, (recordemos que Wake describió 31 code smells y Fowler 24 en su última revisión). En la &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;tesis de master de Jerzyk&lt;/a&gt; se pueden encontrar descripciones y discusiones sobre cada uno de estos 56 code smells.&lt;/p&gt;

&lt;p&gt;Analizando los criterios de clasificación de las taxonomías propuestas anteriormente, Jerzyk encuentra tres criterios significativos para categorizar code smells:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Obstruction&lt;/strong&gt;: Este es el criterio usado por Mäntylä et al para clasificar los smells en su taxonomía y el más popular. Este criterio nos informa sobre el tipo de problema que un code smell causa en el código (lo que hacen difícil o las prácticas o principios que rompen). En la tesis actualizan la taxonomía de Mäntylä, añadiendo tres nuevos grupos: &lt;strong&gt;Data Dealers&lt;/strong&gt;, &lt;strong&gt;Functional Abusers&lt;/strong&gt; y &lt;strong&gt;Lexical Abusers&lt;/strong&gt;. A continuación presentamos un mapa mental que muestra la clasificación de los 56 code smells siguiendo únicamente este criterio.&lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_taxonomy_jerzyk.png&quot; alt=&quot;Taxonomía de Jerzyk usando sólo el criterio de obstruction&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Taxonomía de Jerzyk usando sólo el criterio de obstruction.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Expanse&lt;/strong&gt;: Inspirado por la taxonomía de Wake, este criterio habla de si el code smell puede ser observado en un contexto reducido (dentro de una clase) o si se necesita considerar un contexto más amplio (entre varias clases). Las posibles categorías son &lt;strong&gt;Within Class&lt;/strong&gt; y &lt;strong&gt;Between Classes&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Occurrence&lt;/strong&gt;: También inspirado por la taxonomía de Wake, este criterio está relacionado con la localización donde (o el método por el cuál) se puede detectar un code smell. Las posibles categorías son &lt;strong&gt;Names&lt;/strong&gt;, &lt;strong&gt;Conditional Logic&lt;/strong&gt;, &lt;strong&gt;Message Calls&lt;/strong&gt;, &lt;strong&gt;Unnecessary Complexity&lt;/strong&gt;, &lt;strong&gt;Responsibility&lt;/strong&gt;, &lt;strong&gt;Interfaces&lt;/strong&gt;, &lt;strong&gt;Data&lt;/strong&gt;, &lt;strong&gt;Duplication&lt;/strong&gt; y &lt;strong&gt;Measured Smells&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A continuación presentamos una tabla con los 56 code smells clasificados por Jerzyk en su tesis usando los tres criterios comentados anteriormente:&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_code_smells&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;table class=&quot;zebraTable&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Code Smell&lt;/th&gt;
      &lt;th&gt;Obstruction&lt;/th&gt;
      &lt;th&gt;Expanse&lt;/th&gt;
      &lt;th&gt;Occurrence&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Long Method&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Large Class&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Long Parameter List&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Primitive Obsession&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Data Clumps&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Null Check&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Oddball Solution&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Required Setup/Teardown&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Combinatorial Explosion&lt;/td&gt;
      &lt;td&gt;Bloaters&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Parallel Inheritance Hierarchies&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Divergent Change&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Shotgun Surgery&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Flag Argument&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Callback Hell&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dubious Abstraction&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Special Case&lt;/td&gt;
      &lt;td&gt;Change Preventers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Feature Envy&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Type Embedded In Name&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Indecent Exposure&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fate over Action&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Afraid to Fail&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Binary Operator in Name&lt;/td&gt;
      &lt;td&gt;Couplers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tramp Data&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hidden Dependencies&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Global Data&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Message Chain&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Message Calls&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Middle Man&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Message Calls&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Insider Trading&lt;/td&gt;
      &lt;td&gt;Data Dealers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Lazy Element&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Speculative Generality&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dead Code&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Duplicate Code&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;“What” Comments&lt;/td&gt;
      &lt;td&gt;Dispensables&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mutable Data&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Imperative Loops&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Side Effects&lt;/td&gt;
      &lt;td&gt;Functional Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Responsibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Uncommunicative Name&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Magic Number&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inconsistent Names&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Boolean Blindness&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fallacious Comment&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fallacious Method Name&lt;/td&gt;
      &lt;td&gt;Lexical Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Complicated Boolean Expressions&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Obscured Intent&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vertical Separation&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Measured Smells&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Complicated Regex Expression&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Names&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inconsistent Style&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Status Variable&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Clever Code&lt;/td&gt;
      &lt;td&gt;Obfuscators&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Unnecessary Complexity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Temporary Fields&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Conditional Complexity&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Within&lt;/td&gt;
      &lt;td&gt;Conditional Logic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Refused Bequest&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Alternative Classes with Different Interfaces&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Duplication&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inappropriate Static&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Base Class Depends on Subclass&lt;/td&gt;
      &lt;td&gt;O-O Abusers&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Incomplete Library Class&lt;/td&gt;
      &lt;td&gt;Other&lt;/td&gt;
      &lt;td&gt;Between&lt;/td&gt;
      &lt;td&gt;Interfaces&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Algunos de los nombres en la tabla son diferentes de los que suelen aparecer en la literatura. Los cambios de nombre fueron debidos a la introducción de nombre más actualizados, como es el caso, por ejemplo, de &lt;em&gt;Lazy Element&lt;/em&gt; o &lt;em&gt;Insider Trading&lt;/em&gt; que antes se llamaban &lt;em&gt;Lazy Class&lt;/em&gt; e &lt;em&gt;Inappropriate Intimacy&lt;/em&gt;, respectivamente.&lt;/p&gt;

&lt;p&gt;Hay varios smells que son nuevos. Algunos como &lt;em&gt;Afraid to Fail&lt;/em&gt;, &lt;em&gt;Binary Operator in Name&lt;/em&gt;, &lt;em&gt;Clever Code&lt;/em&gt;, &lt;em&gt;Inconsistent Style&lt;/em&gt;, y &lt;em&gt;Status Variable&lt;/em&gt;, son ideas completamente nuevas. 
Otros son conceptos ya existentes en la literatura pero que no se habían considerado en el contexto de los code smells: &lt;em&gt;Boolean Blindness&lt;/em&gt; o &lt;em&gt;Callback Hell&lt;/em&gt;. Tres de ellos proponen alternativas para code smells que están siendo cuestionados en la literatura: &lt;em&gt;“What” Comment&lt;/em&gt; como alternativa para &lt;em&gt;Comments&lt;/em&gt;, &lt;em&gt;Fate over Action&lt;/em&gt; como alternativa para &lt;em&gt;Data Class&lt;/em&gt;, e &lt;em&gt;Imperative Loops&lt;/em&gt; como alternativa para &lt;em&gt;Loops&lt;/em&gt; (ver la &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;tesis de Jerzyk&lt;/a&gt; para profundizar en por qué estos code smells originales son discutibles). Otros generalizan otros conceptos problemáticos que han surgido en la literatura: &lt;em&gt;Complicated Regex Expression&lt;/em&gt;, &lt;em&gt;Dubious Abstraction&lt;/em&gt;, &lt;em&gt;Fallacious Comment&lt;/em&gt;, &lt;em&gt;Fallacious Method Name&lt;/em&gt;. Por último, un problema conocido (especialmente en el campo de la programación funcional), pero que no se ha considerado hasta ahora como code smell: &lt;em&gt;Side Effects&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;jerzyk_code_smell_online_catalog&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una cosa super útil y práctica para desarrolladores que aporta el trabajo de Jerzyk es la creación de un &lt;a href=&quot;https://luzkan.github.io/smells/&quot;&gt;catálogo online de code smells&lt;/a&gt; que incluía cuando se publicó los 56 code smells que aparecen en la tabla. Este catálogo es un sitio web accesible y buscable. En la fecha de publicación de este post, el catálogo contiene 56 code smells.&lt;/p&gt;

&lt;p&gt;En el catálogo se pueden buscar los smells por diferentes criterios de clasificación.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_catalog_usage_example.png&quot; alt=&quot;Ejemplo de búsqueda en el catálogo online de code smells de Jerzyk&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Ejemplo de búsqueda en el catálogo online de code smells de Jerzyk.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Por ejemplo, esta captura de pantalla muestra el resultado de buscar code smells que sean &lt;em&gt;OO Abusers&lt;/em&gt; y que afecten a &lt;em&gt;Interfaces&lt;/em&gt;: &lt;em&gt;Refused Bequest&lt;/em&gt;, &lt;em&gt;Base Class depends on Subclass&lt;/em&gt; e &lt;em&gt;Inappropriate Static&lt;/em&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/code_smells_in_jerzyk_catalog_example.png&quot; alt=&quot;Code smell en el catálogo online de Jerzyk&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Code smell en el catálogo online de Jerzyk.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Para cada smell el catálogo presentan las siguientes secciones: &lt;strong&gt;Smell&lt;/strong&gt; (discusión del smell), &lt;strong&gt;Causation&lt;/strong&gt; (posibles causas del code smell), &lt;strong&gt;Problems&lt;/strong&gt; (problemas que el smell puede causar o principios de diseño que viola), &lt;strong&gt;Example&lt;/strong&gt; (ejemplos de código mínimo que ilustran los posibles síntomas de un code smell y muestran una posible solución), &lt;strong&gt;Refactoring&lt;/strong&gt; (posibles refactorings) y &lt;strong&gt;Sources&lt;/strong&gt; (artículos o libros en los que se ha hablado de este code smell). También incluye un recuadro en el que aparece información sobre posibles &lt;strong&gt;aliases&lt;/strong&gt; del code smell, la &lt;strong&gt;categoría&lt;/strong&gt; a la que pertenece según los criterios de &lt;strong&gt;obstruction&lt;/strong&gt;, &lt;strong&gt;occurrence&lt;/strong&gt; y &lt;strong&gt;expanse&lt;/strong&gt;, los &lt;strong&gt;smells relacionados&lt;/strong&gt; y su relación con ellos, y el &lt;strong&gt;origen histórico&lt;/strong&gt; del code smell.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;conclusions&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusiones&quot;&gt;Conclusiones.&lt;/h2&gt;

&lt;p&gt;Desde que se acuñó el concepto de code smell en 1999 han aparecido muchos nuevos smells. Las presentaciones planas en forma de catálogo son difíciles de recordar, y no ayudan a resaltar las relaciones que existen entre diferentes code smells.&lt;/p&gt;

&lt;p&gt;Hemos presentado varias taxonomías de code smells que nos pueden ayudar a ver los code smells desde diferentes puntos de vista y relacionarlos unos con otros según diferentes criterios: los problemas que producen en el código, dónde se detectan o el contexto que es necesario tener en cuenta para detectarlos.&lt;/p&gt;

&lt;p&gt;Estos agrupamientos significativos de code smells nos ayudarán a entenderlos y a recordarlos mejor que las listas planas de los catálogos.&lt;/p&gt;

&lt;p&gt;Por último queremos destacar el &lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;reciente trabajo de Marcel Jerzyk&lt;/a&gt; que no sólo ha propuesto nuevos smells y ha creado una nueva taxonomía multicriterio, sino que además ha puesto a nuestra disposición un &lt;a href=&quot;https://luzkan.github.io/smells/&quot;&gt;catálogo online de code smells&lt;/a&gt; en forma de repositorio open-source y sitio web accesible y buscable, que creemos que puede resultar muy útil y práctico tanto para investigadores como para desarrolladores. Los animo a echarle un vistazo.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;greetings&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Agradecimientos.&lt;/h2&gt;

&lt;p&gt;Me gustaría darle las gracias a mis colegas &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt;,  &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de La Torre&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mangelviera/&quot;&gt;Miguel Viera&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/AlfredoCasado/&quot;&gt;Alfredo Casado&lt;/a&gt; por leer los borradores finales de este post y darme feedback. También quería agradecer a &lt;a href=&quot;https://www.pexels.com/es-es/@nikita-3374022/&quot;&gt;nikita&lt;/a&gt; por su foto.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;references&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Referencias.&lt;/h2&gt;

&lt;h4 id=&quot;libros&quot;&gt;Libros.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code 1st edition 1999&lt;/a&gt;, Martin Fowler et al.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/35135772-refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code 2nd edition 2018&lt;/a&gt;, Martin Fowler et al.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://xp123.com/articles/refactoring-workbook/&quot;&gt;Refactoring Workbook&lt;/a&gt;,  William C. Wake&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt;, Joshua Kerievsky&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/55892270-five-lines-of-code&quot;&gt;Five Lines of Code: How and when to refactor&lt;/a&gt;, Christian Clausen&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/cs/book/show/57196550-the-programmer-s-brain&quot;&gt;The Programmer’s Brain&lt;/a&gt;, Felienne Hermans&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;artículos&quot;&gt;Artículos.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.researchgate.net/publication/4036832_A_Taxonomy_and_an_Initial_Empirical_Study_of_Bad_Smells_in_Code&quot;&gt;A Taxonomy and an Initial Empirical Study of Bad Smells in Code&lt;/a&gt;, Mantyla et al, 2003.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.researchgate.net/publication/220277873_Subjective_evaluation_of_software_evolvability_using_code_smells_An_empirical_study&quot;&gt;Subjective evaluation of software evolvability using code smells: An empirical study&lt;/a&gt;, Mantyla et al, 2006.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mmantyla.github.io/BadCodeSmellsTaxonomy&quot;&gt;A Taxonomy for “Bad Code Smells”
&lt;/a&gt;, Mantyla et al, 2006.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/paper.pdf&quot;&gt;Code Smells: A Comprehensive Online Catalog and Taxonomy&lt;/a&gt;, Marcel Jerzyk, 2022.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Luzkan/smells/blob/main/docs/thesis.pdf&quot;&gt;Code Smells: A Comprehensive Online Catalog and Taxonomy Msc. Thesis&lt;/a&gt;, Marcel Jerzyk, 2022.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.100.2813&amp;amp;rep=rep1&amp;amp;type=pdf&quot;&gt;Extending a Taxonomy of Bad Code Smells with
Metrics&lt;/a&gt;, R. Marticorena et al, 2006&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Foto de &lt;a href=&quot;https://www.pexels.com/es-es/@nikita-3374022/&quot;&gt;nikita in Pexels&lt;/a&gt;&lt;/p&gt;
</description>
          <pubDate>2022-09-15T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/09/code-smells-taxonomies-and-catalogs</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/09/code-smells-taxonomies-and-catalogs</guid>
        </item>
      
    
      
        <item>
          <title>Un caso de Shotgun Surgery</title>
          <description>&lt;p&gt;Colaboramos con un cliente en cuyo producto, el SEO es un aspecto muy importante del negocio. En general, el SEO suele ser un aspecto a cuidar, pero en el caso de este cliente el SEO supone una fuente de ingresos considerable.&lt;/p&gt;

&lt;p&gt;Cuando los buscadores analizan las páginas de un producto hay 2 partes importantes para nuestro sistema que se deben indicar al buscador, la indexación de esa página y su canonical.&lt;/p&gt;

&lt;p&gt;Ante páginas similares, el canonical le indica al buscador cuál página queremos posicionar (mediante su url). De esta manera evitamos que los motores de búsqueda nos penalicen al considerar dichas páginas similares como contenido duplicado.&lt;/p&gt;

&lt;p&gt;En el contexto del producto, el SEO además de ser una fuente de ingresos importante, es bastante complejo. Es decir, partimos de una &lt;a href=&quot;https://dzone.com/articles/essential-and-accidental&quot;&gt;complejidad esencial&lt;/a&gt; contenida en reglas de negocio, con una gran variedad de reglas de comportamiento dependiendo de aspectos como la ubicación, el número de resultados, el tipo de búsqueda, etc.&lt;/p&gt;

&lt;h2 id=&quot;situación-del-código&quot;&gt;Situación del código&lt;/h2&gt;

&lt;p&gt;A la complejidad esencial de calcular el canonical de una página y decidir si se indexa o no, se añadía la complejidad accidental provocada por un código en el que las reglas del SEO se encontraban dispersas en 2 zonas de la aplicación, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;. Por suerte, ambas tenían tests.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice1_es.png&quot; alt=&quot;Un caso claro de shotgun surgery...&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Un caso claro de shotgun surgery...&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Los clientes veían estas 2 funcionalidades a través de las interfaces que se muestran a continuación:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/7f7c684c771e1c2c35ca1210c6f0ffbc.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;el-problema&quot;&gt;El problema&lt;/h2&gt;
&lt;p&gt;Viendo los nombres de las interfaces, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;, parece que la responsabilidad de saber si una página se indexa y calcular el canonical están bien segregadas. Sin embargo, cuando se nos pide, por ejemplo, cambiar un aspecto del cálculo del canonical nos vemos obligados a considerar y probablemente cambiar tanto la implementación de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt; como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Es decir, el problema es que si nos piden hacer cambios concretos nos vemos obligados a tocar múltiples zonas. El código presenta un caso claro de un code smell conocido como &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; es una violación del &lt;a href=&quot;https://www.thebigbranchtheory.dev/post/single-responsablity/&quot;&gt;principio de única responsabilidad&lt;/a&gt;. En este caso concreto existe una falta de cohesión a nivel de implementación. Es decir, si bien los ejes de cambio se identificaron correctamente a nivel de interface, las responsabilidades se distribuyeron mal, quedando repartidas entre ambas implementaciones&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La solución para resolver el &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; es segregar las responsabilidades de manera que no violemos el principio de única responsabilidad. Para ellos necesitamos mover
código hacia el lugar donde debería habitar, pero esto no es tan fácil como usar el refactoring &lt;a href=&quot;https://refactoring.com/catalog/moveFunction.html&quot;&gt;Move Function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El problema es que en este caso las reglas se estaban ejecutando en un orden determinado y eso no estaba ni en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt; ni en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; sino en el código cliente. Además, ese orden, determinado por el cliente, no estaba testeado.&lt;/p&gt;

&lt;h2 id=&quot;segregando-las-reglas&quot;&gt;Segregando las Reglas&lt;/h2&gt;
&lt;p&gt;En un caso en el que el cálculo del canonical y el de la indexación no tuvieran que ser ejecutadas en un orden determinado, mover las reglas sólo supondría mover casos de tests entre los tests de las implementaciones y el mover el código correspondiente, usando &lt;a href=&quot;https://refactoring.com/catalog/moveFunction.html&quot;&gt;Move Function&lt;/a&gt;.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice2.png&quot; alt=&quot;Mover responsabilidades es fácil cuando no importa el orden de ejecución&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Mover reglas es fácil cuando no importa el orden de ejecución.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Pero, como explicamos anteriormente, la dependencia entre ambos cálculos introducida por el orden preestablecido y la complejidad de las reglas, hacía que no fuera fácil razonar si era seguro mover la lógica sin cambiar comportamiento. Además, teniendo en cuenta, como ya se explicó, que el SEO supone una fuente de ingresos considerable para este producto, no podíamos aceptar el nivel de riesgo que suponía refactorizar de la manera que hemos explicado.&lt;/p&gt;

&lt;p&gt;Para reducir el riesgo de modificar el comportamiento, lo que hicimos fue extraer una clase, llamada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageIndexer&lt;/code&gt;, cuya responsabilidad era coordinar los cálculos de la indexación y el canonical.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/franreyes/829829d2d830ce97554f384565e19f43.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;A continuación creamos una nueva batería de tests contra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageIndexer&lt;/code&gt; que contenía los casos de tests tanto del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; como de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt;, y añadimos los tests que faltaban para la interacción entre ambas clases. De esta manera estábamos probando no solo cada unidad por separado sino además la interacción (o integración) de ambas.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice3.png&quot; alt=&quot;nuevos tests contra PageIndexer&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Nuevos tests contra la nueva abstracción que encapsula el orden de ejecución de las reglas.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Teniendo estos tests contra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PageIndexer&lt;/code&gt; pudimos empezar a mover a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndexationCalculator&lt;/code&gt; la lógica de indexation que se había filtrado en  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CanonicalCalculator&lt;/code&gt; y viceversa. Para ello movimos las reglas moviendo primero los casos de tests y luego el código correspondiente, usando &lt;a href=&quot;https://refactoring.com/catalog/moveFunction.html&quot;&gt;Move Function&lt;/a&gt;. Al terminar de segregar las responsabilidades, eliminamos los tests que probaban las responsabilidades por separado.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 100%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-09-12-un-caso-de-shotgun-surgery/slice4.png&quot; alt=&quot;test contra cada clase&quot; /&gt;
&lt;figcaption&gt;&lt;strong&gt;Ahora podemos mover reglas con confianza y, al final, eliminar los antiguos tests.&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Hemos presentado un caso de &lt;a href=&quot;https://dzone.com/articles/code-smell-shot-surgery&quot;&gt;Shotgun Surgery&lt;/a&gt; a partir de un caso real y hemos contado como se hizo refactoring para segregar las responsabilidades.&lt;/p&gt;

&lt;p&gt;En un contexto sin las particularidades comentadas, los pasos para resolver el problema habrían dado menos trabajo. Pero el orden de ejecución, la complejidad y el alto valor de negocio en este contexto, hicieron que tuviéramos que trabajar más y no seguir la manera canónica descrita en la mayoría de literatura.&lt;/p&gt;

&lt;p&gt;Si te encuentras en una situación parecida, quizás puedes aplicar algunos de los aspectos de esta solución y reducir el riesgo del cambio.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas&lt;/h2&gt;
&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1]  Los motivos por los que se produjo una mezcla de las responsabilidades pueden estar en el diseño de las interfaces, pero este problema quizás lo tratemos en un futuro post.&lt;/p&gt;

</description>
          <pubDate>2022-09-12T14:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/09/un-caso-de-shotgun-surgery</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/09/un-caso-de-shotgun-surgery</guid>
        </item>
      
    
      
        <item>
          <title>Example of role tests in JavaScript with Jest</title>
          <description>&lt;p&gt;In this post we’ll show our last example applying the concept of role tests, this time in JavaScript using &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt;. Have a look at our &lt;a href=&quot;https://codesai.com/publications/categories/#Role%20Testing&quot;&gt;previous posts on this topic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This example comes from a deliberate practice session we did recently with some developers from &lt;a href=&quot;https://audiense.com/&quot;&gt;Audiense&lt;/a&gt; with whom we’re doing &lt;a href=&quot;https://github.com/Codesai/practice_program_js&quot;&gt;Codesai’s Practice Program in JavaScript&lt;/a&gt; twice a month.&lt;/p&gt;

&lt;p&gt;Similar to what we did in our previous example of role tests in Java, we wrote the following tests to develop two different implementations of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; port while solving the &lt;a href=&quot;https://kata-log.rocks/banking-kata&quot;&gt;Bank Kata&lt;/a&gt;: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryTransactionsRepository&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodePersistTransactionRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These are their tests, respectively:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a6c144388b89532c2e31136ba75cd42e.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7b8a3062378e7fce8265f900265f24b4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;As what happened in our &lt;a href=&quot;https://codesai.com/posts/2022/08/role-tests-junit&quot;&gt;previous post&lt;/a&gt;, both tests contain the same test cases since both tests document and protect the contract of the same role, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt;, which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryTransactionsRepository&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodePersistTransactionRepository&lt;/code&gt; implement.&lt;/p&gt;

&lt;p&gt;Again we’ll use the concept of &lt;em&gt;role tests&lt;/em&gt; to remove that duplication, and make the contract of the role we are implementing more explicit.&lt;/p&gt;

&lt;p&gt;Although &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; does not have something equivalent or similar to the &lt;a href=&quot;https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples&quot;&gt;RSpec’s &lt;em&gt;shared examples&lt;/em&gt; functionality&lt;/a&gt; we used in our &lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;previous example in Ruby&lt;/a&gt;, we can get a very similar result by composing functions.&lt;/p&gt;

&lt;p&gt;First, we wrote the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;behavesLikeATransactionRepository&lt;/code&gt; function. This function contains all the test cases that document the role and protect its contract, and receives as a parameter a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testContext&lt;/code&gt; object containing methods for all the operations that will vary in the different implementations of this integration test.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/63b45e79e01f8b4a9d447ab43018aaf0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice that in the case of &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; we are using &lt;em&gt;composition&lt;/em&gt;, whereas  &lt;a href=&quot;https://codesai.com/posts/2022/08/role-tests-junit&quot;&gt;we used inheritance in the case of Junit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then, we called the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;behavesLikeATransactionRepository&lt;/code&gt; function from the previous tests and implemented a particular version of the methods of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testContext&lt;/code&gt; object for each test.&lt;/p&gt;

&lt;p&gt;This is the new code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryTransactionsRepositoryTest&lt;/code&gt;:
&lt;script src=&quot;https://gist.github.com/trikitrok/ff78d3695bebdb1a5fb53d448cca9e05.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And this is the new code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodePersistTransactionRepository&lt;/code&gt; after the refactoring:
&lt;script src=&quot;https://gist.github.com/trikitrok/97b96cee34dab5dbd7a9abc5bb697c94.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;This new version of the tests not only reduces duplication, but also makes explicit and protects the behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; role. It also makes less error prone the process of adding a new implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; because just by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;behavesLikeATransactionRepository&lt;/code&gt; function, you’d get a checklist of the behaviour you need to implement in order to ensure substitutability, i.e., to ensure the  &lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt; is not violated.&lt;/p&gt;

&lt;p&gt;These role tests using composition are also more readable than &lt;a href=&quot;https://codesai.com/posts/2022/08/role-tests-junit&quot;&gt;the Junit ones&lt;/a&gt;, in my opinion at least :)&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://audiense.com/&quot;&gt;Audiense&lt;/a&gt;’s deliberate practice group for working with us on this kata, and my colleague &lt;a href=&quot;https://twitter.com/rubendm23/&quot;&gt;Rubén Díaz&lt;/a&gt; for co-facilitating the practice sessions with me.&lt;/p&gt;

&lt;p&gt;Thanks to my Codesai colleagues for reading the initial drafts and giving me feedback, and to &lt;a href=&quot;https://www.pexels.com/es-es/@elina-sazonova/&quot;&gt;Elina Sazonova&lt;/a&gt; for the picture.&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;Role tests for implementation of interfaces discovered through TDD&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2022/08/role-tests-junit&quot;&gt;Example of role tests in Java with Junit
&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo from &lt;a href=&quot;https://www.pexels.com/es-es/@elina-sazonova/&quot;&gt;Elina Sazonova in Pexels&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2022-08-04T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/08/role-tests-jest</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/08/role-tests-jest</guid>
        </item>
      
    
      
        <item>
          <title>Example of role tests in Java with Junit</title>
          <description>&lt;p&gt;I’d like to continue with the topic of role tests that we wrote about in a &lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;previous post&lt;/a&gt;, by showing an example of how it can be applied in Java to reduce duplication in your tests.&lt;/p&gt;

&lt;p&gt;This example comes from a deliberate practice session I did recently with some people from Women Tech Makers Barcelona with whom I’m doing &lt;a href=&quot;https://github.com/Codesai/practice_program&quot;&gt;Codesai’s Practice Program in Java&lt;/a&gt; twice a month.&lt;/p&gt;

&lt;p&gt;Making additional changes to the code that resulted from solving the &lt;a href=&quot;https://kata-log.rocks/banking-kata&quot;&gt;Bank Kata&lt;/a&gt; we wrote the following tests to develop two different implementations of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; port: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryTransactionsRepository&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileTransactionsRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These are their tests, respectively:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8f7b7386baee3a92a979f0a3e503ad88.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/14dd372d5cf8f70c6d7d3fc115afd04c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;As you can see both tests contain the same test cases: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a_transaction_can_be_saved&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transactions_can_be_retrieved&lt;/code&gt; but their implementations are different for each class. This makes sense because both implementations implement the same role, (see our &lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;previous post&lt;/a&gt; to learn how this relates to &lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We can make this fact more explicit by using &lt;em&gt;role tests&lt;/em&gt;. In this case, &lt;a href=&quot;https://junit.org/junit5/&quot;&gt;Junit&lt;/a&gt; does not have something equivalent or similar to the &lt;a href=&quot;https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples&quot;&gt;RSpec’s &lt;em&gt;shared examples&lt;/em&gt; functionality&lt;/a&gt; we used in our &lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;previous example in Ruby&lt;/a&gt;. Nonetheless, we can apply the &lt;a href=&quot;https://en.wikipedia.org/wiki/Template_method_pattern&quot;&gt;Template Method pattern&lt;/a&gt; to write the &lt;em&gt;role test&lt;/em&gt;, so that we remove the duplication, and more importantly make the contract we are implementing more explicit.&lt;/p&gt;

&lt;p&gt;To do that we created an abstract class, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepositoryRoleTest&lt;/code&gt;. This class contains the tests cases that document the role and protect its contract (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a_transaction_can_be_saved&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transactions_can_be_retrieved&lt;/code&gt;) and defines &lt;em&gt;hooks&lt;/em&gt; for the operations that will vary in the different implementations of this integration test
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepareData&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readAllTransactions&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createRepository&lt;/code&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0cb1d891fb778e3b73c9765952cb2a58.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then we made the previous tests extend &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepositoryRoleTest&lt;/code&gt; and implemented the &lt;em&gt;hooks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is the new code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryTransactionsRepositoryTest&lt;/code&gt;:
&lt;script src=&quot;https://gist.github.com/trikitrok/2a2340caf8fb19aa7207416231930318.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And this is the new code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileTransactionsRepositoryTest&lt;/code&gt; after the refactoring:
&lt;script src=&quot;https://gist.github.com/trikitrok/e9c5397f3d01f64ebb67ca159241cfa5.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;This new version of the tests not only reduces duplication, but also makes explicit and protects the behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; role. It also makes less error prone the process of adding a new implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepository&lt;/code&gt; because just by extending the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TransactionsRepositoryRoleTest&lt;/code&gt;, you’d get a checklist of the behaviour you need to implement to ensure substitutability, i.e., to ensure the  &lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt; is not violated.&lt;/p&gt;

&lt;p&gt;Have a look at this &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;’s &lt;a href=&quot;https://github.com/jasongorman/ContractTesting&quot;&gt;repository&lt;/a&gt; to see another example that applies the same technique.&lt;/p&gt;

&lt;p&gt;In a future post we’ll show how we can do the same in JavaScript using &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank the WTM study group, and especially &lt;a href=&quot;https://twitter.com/InmaCNavas&quot;&gt;Inma Navas&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/laura-del-toro-sosa/&quot;&gt;Laura del Toro&lt;/a&gt; for practising with this kata together.&lt;/p&gt;

&lt;p&gt;Thanks to my Codesai colleagues, &lt;a href=&quot;https://twitter.com/InmaCNavas&quot;&gt;Inma Navas&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/laura-del-toro-sosa/&quot;&gt;Laura del Toro&lt;/a&gt; for reading the initial drafts and giving me feedback, and to &lt;a href=&quot;https://www.pexels.com/es-es/@esranurkalay/&quot;&gt;Esranur Kalay&lt;/a&gt; for the picture.&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;Role tests for implementation of interfaces discovered through TDD
&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Erich_Gamma&quot;&gt;Erich Gamma&lt;/a&gt;, &lt;a href=&quot;http://software-pattern.org/Author/29&quot;&gt;Ralph Johnson&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Vlissides&quot;&gt;John Vlissides&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?RichardHelm&quot;&gt;Richard Helm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://codemanship.co.uk/parlezuml/blog/?postid=1183&quot;&gt;101 Uses For Polymorphic Testing (Okay… Three)&lt;/a&gt;, &lt;a href=&quot;http://codemanship.co.uk/parlezuml/blog/&quot;&gt;Jason Gorman&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jasongorman/ContractTesting&quot;&gt;Contract Testing example
 repository&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo from &lt;a href=&quot;https://www.pexels.com/es-es/@esranurkalay/&quot;&gt;Esranur Kalay
 in Pexels&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2022-08-02T05:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/08/role-tests-junit</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/08/role-tests-junit</guid>
        </item>
      
    
      
        <item>
          <title>Simple example of property-based testing</title>
          <description>&lt;h2&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;We were recently writing tests to characterise a legacy code at a client that was being used to encrypt and decrypt UUIDs using a &lt;a href=&quot;https://en.wikipedia.org/wiki/Cipher&quot;&gt;cipher algorithm&lt;/a&gt;. We have simplified the client’s code to remove some distracting details and try to highlight the key ideas we’d like to transmit.&lt;/p&gt;

&lt;p&gt;In this post we’ll show how we used &lt;a href=&quot;https://en.wikipedia.org/wiki/Data-driven_testing&quot;&gt;parameterized tests&lt;/a&gt; to test the encryption and decryption functions, and how we applied &lt;a href=&quot;https://ferd.ca/property-based-testing-basics.html&quot;&gt;property-based testing&lt;/a&gt; to explore possible edge cases using a very useful pattern to discover properties.&lt;/p&gt;

&lt;p&gt;Finally, we’ll discuss the resulting tests.&lt;/p&gt;

&lt;h2&gt;Testing the encryption and decryption functions.&lt;/h2&gt;

&lt;p&gt;We started by writing examples to fixate the behaviour of the encryption function. Notice how we used &lt;em&gt;parameterized tests&lt;/em&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; to avoid the duplication that having a different test for each example would have caused:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7faba1ee6a9b03285fae19a87de2f226.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then we wrote more &lt;em&gt;parameterized tests&lt;/em&gt; for the decryption function. Since the encryption and decryption functions are inverses of each other, we could use the same examples that we had used for the encryption function. Notice how the roles of being input and expected output change for the parameters of the new test.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c11eaad96e87903fb22a107cf0e71e3a.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;exploring-edge-cases&quot;&gt;Exploring edge cases.&lt;/h3&gt;

&lt;p&gt;You might wonder why we wanted to explore edge cases. Weren’t the &lt;em&gt;parameterized tests&lt;/em&gt; enough to characterise this legacy code?&lt;/p&gt;

&lt;p&gt;Even though, the &lt;em&gt;parameterized tests&lt;/em&gt; that we wrote for both functions were producing a high &lt;a href=&quot;https://en.wikipedia.org/wiki/Code_coverage&quot;&gt;test coverage&lt;/a&gt;, coverage only “covers” code that is already there. We were not sure if there could be any edge cases, that is, inputs for which the encryption and decryption functions might not behave correctly. We’ve found edge cases in the past even in code with 100% unit test coverage.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.applause.com/blog/how-to-find-test-edge-cases&quot;&gt;Finding edge cases is hard work&lt;/a&gt; which sometimes might require &lt;a href=&quot;https://en.wikipedia.org/wiki/Exploratory_testing&quot;&gt;exploratory testing&lt;/a&gt; by specialists. It would be great to automatically explore some behaviour to find possible edge cases so we don’t have to find them ourselves or some QA specialists. In some cases, we can leverage &lt;em&gt;property-based testing&lt;/em&gt; to do that exploration for us&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the most difficult parts of using &lt;em&gt;property-based testing&lt;/em&gt; is finding out what properties we should use. Fortunately, there are several &lt;em&gt;approaches or patterns for discovering adequate properties&lt;/em&gt; to apply &lt;em&gt;property-based testing&lt;/em&gt; to a given problem. &lt;a href=&quot;https://scottwlaschin.com/&quot;&gt;Scott Wlaschin&lt;/a&gt; wrote a great article in which he explains several of those patterns&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It turned out that the problem we were facing matched directly to one of the patterns described by Wlaschin, the one he calls &lt;a href=&quot;https://fsharpforfunandprofit.com/posts/property-based-testing-2/#there-and-back-again&quot;&gt;“There and back again”&lt;/a&gt;(also known as &lt;em&gt;“Round-tripping”&lt;/em&gt; or &lt;em&gt;“Symmetry”&lt;/em&gt; pattern).&lt;/p&gt;

&lt;p&gt;According to Wlaschin &lt;em&gt;“There and back again”&lt;/em&gt; properties &lt;em&gt;“are based on combining an operation with its inverse, ending up with the same value you started with”&lt;/em&gt;.
As we said before, in our case &lt;em&gt;the decryption and encryption functions were inverses of each other&lt;/em&gt; so the &lt;em&gt;“There and back again”&lt;/em&gt; pattern was likely to lead us to a useful property.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/roundtrip_pbt.jpg&quot; alt=&quot;There and back again diagram.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 100%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once we knew which property to use it was very straightforward to add a property-based test for it. We used the &lt;a href=&quot;https://jqwik.net/&quot;&gt;jqwik&lt;/a&gt; library. We like it because it has very good documentation and it is integrated with Junit.&lt;/p&gt;

&lt;p&gt;Using &lt;em&gt;jqwik&lt;/em&gt; functions we wrote a generator of UUIDs (have a look at the &lt;a href=&quot;https://jqwik.net/docs/current/user-guide.html#customized-parameter-generation&quot;&gt;documentation on how to generate customised parameters&lt;/a&gt;), we then wrote the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_is_the_inverse_of_encrypt&lt;/code&gt; property:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a98452753a1299bff9df2a8e7b8f370d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;By default &lt;em&gt;jqwik&lt;/em&gt; checks the property with 1000 new randomly generated UUIDs every time this test runs. This allows us to gradually explore the set of possible examples in order to find edge cases that we have not considered.&lt;/p&gt;

&lt;h2&gt;Discussion.&lt;/h2&gt;

&lt;p&gt;If we examine the resulting tests we may think that the property-based tests have made the example-based tests redundant. Should we delete the example-based tests and keep only the property-based ones?&lt;/p&gt;

&lt;p&gt;Before answering this question, let’s think about each type of test from different points of view.&lt;/p&gt;

&lt;h4 id=&quot;understandability&quot;&gt;Understandability.&lt;/h4&gt;

&lt;p&gt;Despite being parameterized, it’s relatively easy to see which inputs and expected outputs are used by the &lt;em&gt;example-based tests&lt;/em&gt; because they are literal values provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generateCipheringUuidExamples&lt;/code&gt; method. Besides, this kind of testing was more familiar to the team members.&lt;/p&gt;

&lt;p&gt;In contrast, the UUID used by the property-based tests to check the property is randomly generated and the team was not familiar with property-based testing.&lt;/p&gt;

&lt;h4 id=&quot;granularity&quot;&gt;Granularity.&lt;/h4&gt;

&lt;p&gt;Since we are using a property that uses the &lt;em&gt;“There and back again”&lt;/em&gt; pattern, if there were an error, we wouldn’t know whether the problem was in the encryption or the decryption function, not even after the &lt;em&gt;shrinking process&lt;/em&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. We’d only know the initial UUID that made the property fail.&lt;/p&gt;

&lt;p&gt;This might not be so when using other property patterns. For instance, when using a property based on the &lt;a href=&quot;https://fsharpforfunandprofit.com/posts/property-based-testing-2/#the-test-oracle&quot;&gt;“The test oracle”&lt;/a&gt; pattern, we’d know the input and the actual and expected outputs in case of an error.&lt;/p&gt;

&lt;p&gt;In contrast, using example-based testing it would be very easy to identify the location of the problem.&lt;/p&gt;

&lt;h4 id=&quot;confidence-thoroughness-and-exploration&quot;&gt;Confidence, thoroughness and exploration.&lt;/h4&gt;

&lt;p&gt;The example-based tests specify behaviour using concrete examples in which we set up concrete scenarios, and then check whether the effects produced by the behaviour match what we expect. In the case of the cipher, we pass an input to the functions and assert that their output is what we expect. The testing is reduced just to the arbitrary examples we were able to come up with, but there’s a “gap between what we claim to be testing and what we’re actually testing”&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;: why those arbitrary examples? Does the cipher behave correctly for any possible example?&lt;/p&gt;

&lt;p&gt;Property-based testing “approach the question of correctness from a different angle: under what preconditions and constraints (for example, the range of input parameters) should the functionality under test lead to particular postconditions (results of a computation), and which invariants should never be violated in the course?”&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. With property-based testing we are not limited to the arbitrary examples we were able to come up with as in example-based testing. Instead, property-based testing gives us thoroughness and the ability to explore because it’ll try to find examples that falsify a property every time the test runs. I think this ability to explore makes them more dynamic.&lt;/p&gt;

&lt;h4 id=&quot;implementation-independence&quot;&gt;Implementation independence.&lt;/h4&gt;

&lt;p&gt;The example-based tests depend on the implementation of the cypher algorithm, whereas  the property-based tests can be used for any implementation of the cypher algorithm because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_is_the_inverse_of_encrypt&lt;/code&gt; property is an &lt;strong&gt;invariant&lt;/strong&gt; of any cipher algorithm implementation. This makes the property-based tests ideal to write a &lt;em&gt;role test&lt;/em&gt;&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt; that any valid cipher implementation should pass.&lt;/p&gt;

&lt;h4 id=&quot;explicitness-of-invariants&quot;&gt;Explicitness of invariants.&lt;/h4&gt;

&lt;p&gt;In the case of the cipher there’s a relationship between the encryption and decryption functions: they are inverses of each other.&lt;/p&gt;

&lt;p&gt;This relationship might go completely untested using example-based testing if we use unrelated examples to test each of the functions. This means there could be changes to any of the functions that may violate the property while passing the independent separated tests of each function.&lt;/p&gt;

&lt;p&gt;In the parameterized example-based tests we wrote, we implicitly tested this property by using the same set of examples for both functions just changing the roles of input and expected output for each test, but this is limited to the set of examples.&lt;/p&gt;

&lt;p&gt;With property-based testing we are explicitly testing the relation between the two functions and exploring the space of inputs to try to find one that falsifies the property of being inverses of each other.&lt;/p&gt;

&lt;h4 id=&quot;protection-against-regressions&quot;&gt;Protection against regressions.&lt;/h4&gt;

&lt;p&gt;Notice that, in this case, If we deleted the example-based tests and just kept the property-based test using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_is_the_inverse_of_encrypt&lt;/code&gt; property, we could introduce a simple regression by implementing both functions, encrypt and decrypt, as the identity function. That obviously wrong implementation would still fulfil the  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_is_the_inverse_of_encrypt&lt;/code&gt; property, which means that the property-based test using  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_is_the_inverse_of_encrypt&lt;/code&gt; property is not enough on its own to characterise the desired behaviour and protect it against regressions. We also need to at least add example-based testing for one of the cipher functions, either encrypt or decrypt. Notice that this might happen for any property based on &lt;em&gt;“There and back again”&lt;/em&gt; pattern. This might not hold true for different contexts and property patterns.&lt;/p&gt;

&lt;h4 id=&quot;what-we-did&quot;&gt;What we did.&lt;/h4&gt;

&lt;p&gt;Given the previous discussion, we decided to keep both example-based and property-based tests in order to gain exploratory power while keeping familiarity, granularity and protection against regressions.&lt;/p&gt;

&lt;h2&gt;Summary.&lt;/h2&gt;
&lt;p&gt;We’ve shown a simple example of how we applied &lt;a href=&quot;https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests&quot;&gt;JUnit 5 parameterized tests&lt;/a&gt; to test the encryption and decryption functions of a cipher algorithm for UUIDs.&lt;/p&gt;

&lt;p&gt;Then we showed a simple example of how we can use property-based testing to explore our solution and find edge cases. We also talked about how discovering properties can be the most difficult part of property-based testing, and how there are patterns that can be used to help us to discover them.&lt;/p&gt;

&lt;p&gt;Finally, we discussed the resulting example-based and property-based tests from different points of view.&lt;/p&gt;

&lt;p&gt;We hope this post will motivate you to start exploring property-based testing as well. If you want to learn more, follow the references we provide and start playing. Also have a look at the other &lt;a href=&quot;https://codesai.com/publications/categories/#Property-based%20testing&quot;&gt;posts exploring property-based testing in our blog&lt;/a&gt; we have written in the past.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank my Codesai colleagues for reading the initial drafts and giving me feedback.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] The experience of writing parameterized tests using JUnit 5 is so much better than it used to be with JUnit 4!&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Have a look at this other &lt;a href=&quot;http://garajeando.blogspot.com/2015/07/applying-property-based-testing-on-my.html&quot;&gt;post&lt;/a&gt; in which I describe how &lt;em&gt;property-based tests&lt;/em&gt; were able to find edge cases that I had not contemplated in a code with 100% test coverage that had been written using TDD.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3]  &lt;a href=&quot;https://scottwlaschin.com/&quot;&gt;Scott Wlaschin&lt;/a&gt;’s article, &lt;a href=&quot;https://fsharpforfunandprofit.com/posts/property-based-testing-2/&quot;&gt;Choosing properties for property-based testing&lt;/a&gt;, is a great post in which he manages to explain the patterns that have helped him the most, to discover the properties that are applicable to a given problem. Besides the “There and back again” pattern, I’ve applied the [“The test oracle”][https://fsharpforfunandprofit.com/posts/property-based-testing-2/#the-test-oracle] on several occasions. Some time ago, I wrote a &lt;a href=&quot;http://garajeando.blogspot.com/2015/07/applying-property-based-testing-on-my.html&quot;&gt;post explaining how I used it to apply property-based testing to an implementation of a binary search tree&lt;/a&gt;. 
Another interesting article about the same topic is &lt;a href=&quot;https://blog.ssanj.net/posts/2016-06-26-property-based-testing-patterns.html&quot;&gt;Property-based Testing Patterns&lt;/a&gt;, &lt;a href=&quot;https://blog.ssanj.net/&quot;&gt;Sanjiv Sahayam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] “Shrinking is the mechanism by which a property-based testing framework can be told how to simplify failure cases enough to let it figure out exactly what the minimal reproducible case is.” from &lt;a href=&quot;https://propertesting.com/book_shrinking.html&quot;&gt;chapter 8&lt;/a&gt; of &lt;a href=&quot;https://ferd.ca/&quot;&gt;Fred Hebert&lt;/a&gt;’s &lt;a href=&quot;https://propertesting.com/toc.html&quot;&gt;PropEr Testing online book&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] From &lt;a href=&quot;https://twitter.com/DRMacIver&quot;&gt;David MacIver&lt;/a&gt;’s &lt;a href=&quot;https://increment.com/testing/in-praise-of-property-based-testing/&quot;&gt;In praise of property-based testing&lt;/a&gt; post. According to David MacIver “the problem with example-based tests is that they end up making far stronger claims than they are actually able to demonstrate”.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] From &lt;a href=&quot;https://johanneslink.net/english.html&quot;&gt;Johannes Link&lt;/a&gt;’s &lt;a href=&quot;https://blogs.oracle.com/javamagazine/post/know-for-sure-with-property-based-testing&quot;&gt;Know for Sure with Property-Based Testing
&lt;/a&gt; post.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Have a look at &lt;a href=&quot;https://codesai.com/posts/2022/04/role-tests&quot;&gt;our recent post about role tests&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ferd.ca/property-based-testing-basics.html&quot;&gt;Property-based Testing Basics&lt;/a&gt;, &lt;a href=&quot;https://ferd.ca/&quot;&gt;Fred Hebert&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://propertesting.com/toc.html&quot;&gt;PropEr Testing online book&lt;/a&gt;, &lt;a href=&quot;https://ferd.ca/&quot;&gt;Fred Hebert&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://fsharpforfunandprofit.com/posts/property-based-testing-2/&quot;&gt;Choosing properties for property-based testing&lt;/a&gt;, &lt;a href=&quot;https://scottwlaschin.com/&quot;&gt;Scott Wlaschin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.ssanj.net/posts/2016-06-26-property-based-testing-patterns.html&quot;&gt;Property-based Testing Patterns&lt;/a&gt;, &lt;a href=&quot;https://blog.ssanj.net/&quot;&gt;Sanjiv Sahayam&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cipher&quot;&gt;Cipher algorithm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://increment.com/testing/in-praise-of-property-based-testing/&quot;&gt;In praise of property-based testing&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/DRMacIver&quot;&gt;David MacIver&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/javamagazine/post/know-for-sure-with-property-based-testing&quot;&gt;Know for Sure with property-based Testing
&lt;/a&gt;, &lt;a href=&quot;https://johanneslink.net/english.html&quot;&gt;Johannes Link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo from &lt;a href=&quot;https://pixabay.com/&quot;&gt;Pixabay&lt;/a&gt; in &lt;a href=&quot;https://www.pexels.com&quot;&gt;Pexels&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2022-06-20T11:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/06/simple-pbt-example</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/06/simple-pbt-example</guid>
        </item>
      
    
      
        <item>
          <title>Listening to test smells: detecting lack of cohesion and violations of encapsulation</title>
          <description>&lt;h2&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;We’d like to show another example of how difficulties found while testing can signal design problems in our code&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We believe that a good design is one that supports the evolution of a code base at a sustainable pace and that testability is a requirement for evolvability. This is not something new, we can find this idea in many places.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt; says &lt;em&gt;“every time you encounter a testability problem, there is an underlying design problem”&lt;/em&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.natpryce.com/articles.html&quot;&gt;Nat Pryce&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/sf105?lang=en&quot;&gt;Steve Freeman&lt;/a&gt; also think that this relationship between testability and good design exists&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“[…] We’ve found that the qualities that make an object easy to test also make our code responsive to change”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;and also use it to detect design problems and know what to refactor:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“[…] where we find that our tests are awkward to write, it’s usually because the design of our target code can be improved”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;and to improve their TDD practice:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“[…] sensitise yourself to find the rough edges in your tests and use them for rapid feedback about what to do with the code. […] don’t stop at the immediate problem (an ugly test) but look deeper for why I’m in this situation (weakness in the design) and address that.”&lt;/em&gt;&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why they devoted talks, several posts and a chapter of their GOOS book (chapter 20) to listening to the tests&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; and even added it to the TDD cycle steps:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/listening-to-tests.svg&quot; alt=&quot;TDD cycle steps including listening to the tests.&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 50%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next we’ll show you an example of how we’ve recently applied this in a client.&lt;/p&gt;

&lt;h2&gt;The problem.&lt;/h2&gt;

&lt;p&gt;Recently I was asked to help a pair that was developing a new feature in a legacy code base of one of our clients. They were having problems with the following test&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8e50ae685aa01d16703d88371bec232d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;that was testing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/db615b7ddea29d5280db20ee4a5f55c3.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;They had managed to test drive the functionality but they were unhappy with the results. The thing that was bothering them was the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resetCache&lt;/code&gt; method in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; class. As its name implies, its intent was to reset the cache. This would have been fine, if this had been a requirement, but that was not the case. The method had been added only for testing purposes.&lt;/p&gt;

&lt;p&gt;Looking at the code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; you can learn why.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cachedSearchResult&lt;/code&gt; field is static and that was breaking the isolation between tests.
Even though they were using different instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; in each test, they were sharing the same value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cachedSearchResult&lt;/code&gt; field because static state is associated with the class. So a new public method, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resetCache&lt;/code&gt;, was added to the class only to ensure isolation between different tests.&lt;/p&gt;

&lt;p&gt;Adding code to your production code base just to enable unit testing is a unit testing anti-pattern&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;, but they didn’t know how to get rid of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resetCache&lt;/code&gt; method, and that’s why I was called in to help.&lt;/p&gt;

&lt;p&gt;Let’s examine the tests in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepositoryTests&lt;/code&gt; to see if they can point to more fundamental design problems.&lt;/p&gt;

&lt;p&gt;Another thing we can notice is that the tests can be divided in to sets that are testing two very different behaviours:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;One set of tests, comprised of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;maps_all_ads_with_photo_to_gallery_ads&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ignore_ads_with_no_photos_in_gallery_ads&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when_no_ads_are_found_there_are_no_gallery_ads&lt;/code&gt;, is testing the code that obtains the list of gallery ads;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;whereas, the other set, comprised of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when_cache_has_not_expired_the_cached_values_are_used&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when_cache_expires_new_values_are_retrieved&lt;/code&gt; is testing the life and expiration of some cached values.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This lack of focus was a hint that the production class might lack cohesion, i.e., it might have several responsibilities.&lt;/p&gt;

&lt;p&gt;It turns out that there was another code smell that confirmed our suspicion. Notice the boolean parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; constructor.
That was a clear example of a &lt;strong&gt;flag argument&lt;/strong&gt;&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt; was making the class behave differently depending on its value:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It cached the list of gallery ads when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt; was true.&lt;/li&gt;
  &lt;li&gt;It did not cache them when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt; was false.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After seeing all this, I told the pair that the real problem was the lack of cohesion and that we’d have to go more object-oriented in order to avoid it. After that refactoring the need for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resetCache&lt;/code&gt; would disappear.&lt;/p&gt;

&lt;h2&gt;Going more OO to fix the lack of cohesion.&lt;/h2&gt;

&lt;p&gt;To strengthen cohesion we need to separate concerns. Let’s see the problem from the point of view of the client of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; class, (this point of view is generally very useful because the test is also a client of the tested class) and think about what it would want from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;. It would be something like &lt;em&gt;“obtain the gallery ads for me”&lt;/em&gt;, that would be the responsibility of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;, and that’s what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GalleryAdsRepository&lt;/code&gt; represents.&lt;/p&gt;

&lt;p&gt;Notice that to satisfy that responsibility we do not need to use a cache, only get some ads from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdsRepository&lt;/code&gt; and map them (the original functionality also included some enrichments using data from other sources but we remove them from the example for the sake of simplicity). Caching is an optimization that we might do or not, it’s a refinement of how we satisfy the responsibility but it’s not necessary to satisfy it, so, we might say that caching changes the &lt;em&gt;“how”&lt;/em&gt; but not the &lt;em&gt;“what”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This matches very well with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Proxy_pattern&quot;&gt;Proxy design pattern&lt;/a&gt; &lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt; because it allows us to attach additional behaviour (caching) to the basic behaviour that satisfied the role that the client needs (&lt;em&gt;“obtain the gallery ads for me”&lt;/em&gt;). This way instead of having a flag parameter (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt; in the original code) to control whether we cache or not, we might add caching by composing two objects that implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GalleryAdsRepository&lt;/code&gt; interface. One of them is the object with the basic behaviour, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;, that would be in charge of getting ads from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdsRepository&lt;/code&gt; and mapping them to gallery ads, and the other one, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CachedGalleryAdsRepository&lt;/code&gt;, would cache the gallery ads. The object with the basic behaviour might not be called if the proxy decides it does not need to do so.&lt;/p&gt;

&lt;p&gt;So we moved the responsibility of caching the ads to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CachedGalleryAdsRepository&lt;/code&gt; class which wraps the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;This is the code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CachedGalleryAdsRepository&lt;/code&gt; class:
&lt;script src=&quot;https://gist.github.com/trikitrok/965181644c5aa7e7b51ae0944634611c.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;and these are its tests:
&lt;script src=&quot;https://gist.github.com/trikitrok/df4e6039d77e019bc45fee93cc9c5b19.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Notice how we found here again the two tests that were previously testing the life and expiration of the cached values in the test of the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when_cache_has_not_expired_the_cached_values_are_used&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when_cache_expires_new_values_are_retrieved&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, looking at them more closely, we can see how, in this new design, those tests are also simpler because they don’t know anything about the inner details
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;. They only know about the logic related to the life and expiration of the cached values and that when the cache is refreshed they call a collaborator that implements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GalleryAdsRepository&lt;/code&gt; interface, this means that now we’re caching gallery ads instead of an instance of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SearchResult&lt;/code&gt; and we don’t know anything about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdsRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On a side note, we also improved the code by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Duration&lt;/code&gt; value object from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.time&lt;/code&gt; to remove the &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=9&quot;&gt;primitive obsession smell&lt;/a&gt; caused by using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt; to represent milliseconds.&lt;/p&gt;

&lt;p&gt;Another very important improvement is that we don’t need the static field anymore.&lt;/p&gt;

&lt;p&gt;And what about  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;?&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/fa4a85345fbc40e641fce5035669886a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;If we have a look at its new code, we can notice that its only concern is how to obtain the list of gallery ads and mapping them from the result of its collaborator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdsRepository&lt;/code&gt;, and it does not know anything about caching values. So the new design is more cohesive than the original one.
Notice how we removed both the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resetCache&lt;/code&gt; method that was before polluting its interface only for testing purposes, and the flag argument, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;useCache&lt;/code&gt;, in the constructor.&lt;/p&gt;

&lt;p&gt;We also reduced its number of collaborators because there’s no need for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; anymore. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; collaborator was needed for a different concern that is now taken care of by the proxy: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CachedGalleryAdsRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These design improvements are reflected in its new tests. They are now more focused, and can only fail if the obtention of the gallery ads breaks. Having only one reason to fail comes from testing a more cohesive unit with only one reason to change.  Notice how these tests coincide with the subset of tests concerned with testing the same behaviour in the original tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/35749a8b111aacb23f0d8cd290cc7e79.js&quot;&gt;&lt;/script&gt;

&lt;h2&gt;Persisting the cached values between calls.&lt;/h2&gt;

&lt;p&gt;You might be asking yourselves, how are we going to ensure that the cached values persist between calls now that we don’t have a static field anymore.&lt;/p&gt;

&lt;p&gt;Well, the answer is that we don’t need to keep a static field in our classes for that. The only thing we need is that the composition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CachedGalleryAdsRepository&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RealTimeGalleryAdsRepository&lt;/code&gt; is &lt;em&gt;created only once, and that we use that single instance for the lifetime of the application&lt;/em&gt;. That is a concern that we can address using a different mechanism.&lt;/p&gt;

&lt;p&gt;We usually find in legacy code bases that this need to &lt;em&gt;create something only once, and use that single instance for the lifetime of the application&lt;/em&gt; is met using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Singleton_pattern&quot;&gt;Singleton design pattern&lt;/a&gt; described in the design patterns book. The Singleton design pattern intent is to &lt;em&gt;“ensure that only one instance of the singleton class ever exists; and provide global access to that instance”&lt;/em&gt;. The second part of that intent, &lt;em&gt;“providing global access”&lt;/em&gt;, is problematic because it introduces global state into the application. Using global state creates high coupling (in the form of hidden dependencies and possible actions at a distance) that drastically reduces testability.&lt;/p&gt;

&lt;p&gt;Instead we used the &lt;strong&gt;singleton pattern&lt;/strong&gt;&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;. Notice the lowercase letter. The lowercase ’s’ singleton avoids those testability problems because its intent is only to &lt;em&gt;“ensure that only one instance of some class ever exists because its new operator is called only once”&lt;/em&gt;. The problematic global access part gets removed from the intent. This is done by avoiding mixing object instantiation with business logic by using separated factories that know how to create and wire up all the dependencies using dependency injection.&lt;/p&gt;

&lt;p&gt;We might create this singleton, for instance, by using a dependency injection framework like &lt;a href=&quot;https://github.com/google/guice&quot;&gt;Guice&lt;/a&gt; and its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Singleton&lt;/code&gt; annotation.&lt;/p&gt;

&lt;p&gt;In this case we coded it ourselves:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/082c40d8d869ba568e1da6869aabed07.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the factory method that returns a unique instance of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GalleryAdsRepository&lt;/code&gt; interface that caches values. This factory method is never used by business logic, it’s only used by instantiation logic in factories that know how to create and wire up all the dependencies using dependency injection. This doesn’t introduce testability problems because the unique instance will be injected through constructors by factories wherever is needed.&lt;/p&gt;

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

&lt;p&gt;We show a recent example we found working for a client that illustrates how testability problems may usually point, if we listen to them, to the detection of underlying design problems. In this case the problems in the test were pointing to a lack of cohesion in the production code that was being tested. The original class had too many responsibilities.&lt;/p&gt;

&lt;p&gt;We refactored the production code to separate concerns by going more OO applying the proxy design pattern. The result was more cohesive production classes that led to more focused tests, and removed the design problems we had detected in the original design.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank my Codesai colleagues for reading the initial drafts and giving me feedback.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] We showed another example of this relationship between poor testability and design problems in a previous post: &lt;a href=&quot;https://codesai.com/posts/2019/06/listening-to-tests-to-go-more-oo&quot;&gt;An example of listening to the tests to improve a design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Listen to his great talk about this relationship: &lt;a href=&quot;https://www.youtube.com/watch?v=4cVZvoFGJTU&quot;&gt;The Deep Synergy Between Testability and Good Design&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] This is the complete paragraph from chapter 20, &lt;strong&gt;Listening to the tests&lt;/strong&gt;, of the &lt;a href=&quot;https://www.goodreads.com/en/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;GOOS book&lt;/a&gt;: &lt;em&gt;“Sometimes we find it difficult to write a test for some functionality we want to add to our code. In our experience, this usually means that our design can be improved — perhaps the class is too tightly coupled to its environment or does not have clear responsibilities. When this happens, we first check whether it’s an opportunity to improve our code, before working around the design by making the test more complicated or using more sophisticated tools. We’ve found that the qualities that make an object easy to test also make our code responsive to change.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4]  This quote is from their post &lt;a href=&quot;https://web.archive.org/web/20210415164603/http://www.mockobjects.com/2007/03/synaesthesia-listening-to-test-smells.html&quot;&gt;Synaesthesia: Listening to Test Smells&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5]  Have a look at this interesting &lt;a href=&quot;https://web.archive.org/web/20210426022938/http://www.mockobjects.com/search/label/listening%20to%20the%20tests&quot;&gt;series of posts about listening to the tests&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/sf105?lang=en&quot;&gt;Steve Freeman&lt;/a&gt;. It’s a raw version of the content that you’ll find in chapter 20, &lt;strong&gt;Listening to the tests&lt;/strong&gt;, of their book.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] We have simplified the client’s code to remove some distracting details and try to highlight its key problems.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] &lt;a href=&quot;https://twitter.com/vkhorikov?lang=en&quot;&gt;Vladimir Khorikov&lt;/a&gt; calls this unit testing anti-pattern &lt;a href=&quot;https://enterprisecraftsmanship.com/posts/code-pollution/&quot;&gt;Code pollution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] A &lt;a href=&quot;https://martinfowler.com/bliki/FlagArgument.html&quot;&gt;flag Argument&lt;/a&gt; is a kind of argument that is telling a function or a class to behave in a different way depending on its value. This might be a signal of poor cohesion in the function or class.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] A proxy is a wrapper of an object that implements the same interface and controls access to it. A proxy may restrict what a client does by controlling access to some functionality, or it may restrict what a client knows by performing actions that are invisible and unknown to the client. Some examples of using proxies are caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. See &lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] &lt;a href=&quot;http://misko.hevery.com/about/&quot;&gt;Miško Hevery&lt;/a&gt; talks about the singleton pattern with lowercase ‘s’ in its talk &lt;a href=&quot;https://testing.googleblog.com/2008/11/clean-code-talks-global-state-and.html&quot;&gt;Global State and Singletons
&lt;/a&gt; at  10:20: &lt;em&gt;“Singleton with capital ’S’. Refers to the design pattern where the Singleton has a private constructor and has a global instance variable. Lowercase ’s’ singleton means I only have a single instance of something because I only called the new operator once.”&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/en/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/sf105?lang=en&quot;&gt;Steve Freeman&lt;/a&gt;, &lt;a href=&quot;http://www.natpryce.com/articles.html&quot;&gt;Nat Pryce&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=4cVZvoFGJTU&quot;&gt;The Deep Synergy Between Testability and Good Design&lt;/a&gt;,
&lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85021.Design_Patterns_Explained&quot;&gt;Design Patterns Explained: A New Perspective on Object-Oriented Design&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alshalloway&quot;&gt;Alan Shalloway&lt;/a&gt;, &lt;a href=&quot;https://www.semanticscholar.org/author/James-R.-Trott/46648275&quot;&gt;James R. Trott&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Erich_Gamma&quot;&gt;Erich Gamma&lt;/a&gt;, &lt;a href=&quot;http://software-pattern.org/Author/29&quot;&gt;Ralph Johnson&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Vlissides&quot;&gt;John Vlissides&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?RichardHelm&quot;&gt;Richard Helm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://testing.googleblog.com/2008/11/clean-code-talks-global-state-and.html&quot;&gt;Clean Code Talks - Global State and Singletons
&lt;/a&gt;, &lt;a href=&quot;http://misko.hevery.com/about/&quot;&gt;Miško Hevery&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://code.google.com/archive/p/google-singleton-detector/wikis/WhySingletonsAreControversial.wiki&quot;&gt;Why Singletons Are Controversial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/bliki/FlagArgument.html&quot;&gt;Flag Argument&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/posts/2019/06/listening-to-tests-to-go-more-oo&quot;&gt;An example of listening to the tests to improve a design&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://enterprisecraftsmanship.com/posts/code-pollution/&quot;&gt;Code pollution&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/vkhorikov?lang=en&quot;&gt;Vladimir Khorikov&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/google/guice&quot;&gt;Guice&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/google/guice/wiki/Scopes&quot;&gt;Guice Scopes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo from &lt;a href=&quot;https://www.pexels.com/es-es/@cottonbro/&quot;&gt;cottonbro&lt;/a&gt; in &lt;a href=&quot;https://www.pexels.com&quot;&gt;Pexels&lt;/a&gt;.&lt;/p&gt;

</description>
          <pubDate>2022-05-04T17:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/05/listening-to-test-smells-1</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/05/listening-to-test-smells-1</guid>
        </item>
      
    
      
        <item>
          <title>Role tests for implementation of interfaces discovered through TDD</title>
          <description>&lt;h2&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;Working through the first three iterations of a &lt;a href=&quot;https://github.com/aleasoluciones/pycones2014&quot;&gt;workshop’s exercise&lt;/a&gt;, we produced several &lt;a href=&quot;http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/&quot;&gt;application services&lt;/a&gt; that at some point collaborated with a users &lt;a href=&quot;http://martinfowler.com/eaaCatalog/repository.html&quot;&gt;repository&lt;/a&gt; that we hadn’t yet created so we used a &lt;a href=&quot;https://martinfowler.com/bliki/TestDouble.html&quot;&gt;test double&lt;/a&gt; in its place in their tests.&lt;/p&gt;

&lt;p&gt;These are the tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5ecc37c07ea09664f052.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/b509de86bd8674c8e8cd.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e2ad4df8bbf2c48ae57f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In these tests, every time we allow or expect a method call on our repository double,
we are defining not only &lt;em&gt;the messages that the users repository can respond to&lt;/em&gt; (its &lt;em&gt;public interface&lt;/em&gt;)&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; but also &lt;em&gt;what its clients can expect from each of those messages&lt;/em&gt;, i.e. &lt;em&gt;its contract&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In other words, at the same time we were testing the application services, we &lt;em&gt;defined from the point of view of its clients the responsibilities that the users repository should be accountable for&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The users repository is at the boundary of our domain. It’s a &lt;a href=&quot;https://alistair.cockburn.us/hexagonal-architecture/&quot;&gt;&lt;em&gt;port&lt;/em&gt;&lt;/a&gt; that &lt;em&gt;allows us to not have to know anything about how&lt;/em&gt; users are stored, found, etc. This way we are able to &lt;em&gt;just focus on what its clients want it to do for them&lt;/em&gt;, i.e., &lt;em&gt;its responsibilities&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Focusing on the responsibilities results in more stable interfaces. As I heard &lt;a href=&quot;https://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt; say once:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“You can trade the unpredictability of what others do for the constancy of what you want.”&lt;/em&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which is a very nice way to explain the &lt;em&gt;“Program to an interface, not an implementation”&lt;/em&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; design principle.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How those responsibilities are carried out&lt;/em&gt; is something that each different implementation (or &lt;em&gt;adapter&lt;/em&gt;) of the users repository &lt;em&gt;port&lt;/em&gt; is responsible for. However, the terms of &lt;em&gt;the contract that its clients rely on, must be respected by all of the adapters&lt;/em&gt;. They must play their &lt;em&gt;roles&lt;/em&gt;. In this sense, &lt;em&gt;any adapter must be substitutable by any other without the clients being affected&lt;/em&gt;, (yes, you’re right, it’s the &lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov substitution principle&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;Role or contract tests.&lt;/h2&gt;

&lt;p&gt;The only way to ensure this &lt;em&gt;substitutability&lt;/em&gt; is by testing each adapter to check if it also &lt;em&gt;respects the terms of the contract&lt;/em&gt;, i. e. it &lt;em&gt;fulfils its role&lt;/em&gt;. Those tests would ensure that the &lt;em&gt;Liskov substitution principle&lt;/em&gt; is respected&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will use the term &lt;em&gt;role test&lt;/em&gt; used by Sandi Metz because &lt;em&gt;contract test&lt;/em&gt; has become overloaded&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok, but how can we test that all the possible implementations of the user repository respect the contract without repeating a bunch of test code?&lt;/p&gt;

&lt;h2&gt;Using shared examples in RSpec to write role tests.&lt;/h2&gt;

&lt;p&gt;There’s one very readable way to do it in Ruby using &lt;a href=&quot;https://rspec.info/&quot;&gt;RSpec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We created a &lt;a href=&quot;https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples&quot;&gt;RSpec shared example&lt;/a&gt; in a file named &lt;em&gt;users_repository_role.rb&lt;/em&gt; where we wrote the tests that describes the behaviour that users repository clients were relying on:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/64ac2d7345cbd2c23c1f4c8f5b027c66.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then for each implementation of the users repository you just need to include the role tests using RSpec &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;it_behaves_like&lt;/code&gt; method, as shown in the following two implementations:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1cde4fe0d53e92d3253c.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/18cddf72538835300826.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;You could still add any other test that only has to do with a given implementation in its specific test.&lt;/p&gt;

&lt;p&gt;This solution is very readable and reduces a lot of duplication in the tests. However, the idea of &lt;em&gt;role tests&lt;/em&gt; is not only important from the point of view of avoiding duplication in test code. In dynamic languages, such as Ruby, they also serve as a mean to &lt;em&gt;highlight and document the role of duck types&lt;/em&gt; that might otherwise go unnoticed because there is no interface construct.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank my Codesai colleagues for reading the initial drafts and giving me feedback.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Read more about objects communicating by sending and receiving messages in &lt;a href=&quot;https://wiki.c2.com/?AlanKaysDefinitionOfObjectOriented&quot;&gt;Alan Kay’s Definition Of Object Oriented&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] You can find a slightly different wording of it in her great talk &lt;a href=&quot;https://vimeo.com/26330100&quot;&gt;Less - The Path to Better Design&lt;/a&gt;  at 29’48’’.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Presented in chapter one of &lt;a href=&quot;https://en.wikipedia.org/wiki/Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt; book.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] This is similar to &lt;a href=&quot;http://www.jbrains.ca/&quot;&gt;J. B. Rainsberger&lt;/a&gt;’s idea of &lt;em&gt;contract tests&lt;/em&gt; mentioned in his &lt;a href=&quot;https://vimeo.com/80533536&quot;&gt;Integrated Tests Are A Scam talk&lt;/a&gt; and also to &lt;a href=&quot;http://codemanship.co.uk/parlezuml/blog/&quot;&gt;Jason Gorman&lt;/a&gt;’s idea of &lt;a href=&quot;http://codemanship.co.uk/parlezuml/blog/?postid=1183&quot;&gt;polymorphic testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] For example &lt;a href=&quot;https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)&quot;&gt;Martin Fowler&lt;/a&gt; uses contract test to define a different concept in &lt;a href=&quot;https://martinfowler.com/bliki/ContractTest.html&quot;&gt;Contract Test&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.poodr.com/&quot;&gt;Practical Object-Oriented Design, An Agile Primer Using Ruby&lt;/a&gt;, &lt;a href=&quot;https://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HGT8bKSS6XQ&quot;&gt;Defining Object-Oriented Design&lt;/a&gt;, &lt;a href=&quot;https://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vimeo.com/53154357&quot;&gt;Less - The Path to Better Design&lt;/a&gt;, &lt;a href=&quot;https://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Erich_Gamma&quot;&gt;Erich Gamma&lt;/a&gt;, &lt;a href=&quot;http://software-pattern.org/Author/29&quot;&gt;Ralph Johnson&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Vlissides&quot;&gt;John Vlissides&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?RichardHelm&quot;&gt;Richard Helm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vimeo.com/80533536&quot;&gt;Integrated Tests Are A Scam talk&lt;/a&gt;, &lt;a href=&quot;http://www.jbrains.ca/&quot;&gt;J. B. Rainsberger&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20161231000421/http://codemanship.co.uk/parlezuml/blog/?postid=1183&quot;&gt;101 Uses For Polymorphic Testing (Okay… Three)&lt;/a&gt;, &lt;a href=&quot;https://codemanship.wordpress.com/&quot;&gt;Jason Gorman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo from &lt;a href=&quot;https://www.pexels.com/es-es/@anna-rye-70977670?utm_content=attributionCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=pexels&quot;&gt;Anna Rye in Pexels&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2022-04-03T17:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/04/role-tests</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/04/role-tests</guid>
        </item>
      
    
      
        <item>
          <title>Restringiendo interfaces II: Modelando apariencias</title>
          <description>&lt;p&gt;Volvemos con la segunda parte de &lt;a href=&quot;https://codesai.com/2022/01/restringiendo-interfaces&quot;&gt;Restringiendo Interfaces&lt;/a&gt;. En esta ocasión hablaremos de cómo heredar modelos existentes
puede adulterar su diseño, provocando la ilusión de que es la forma más fiel de modelar el dominio del problema.
En este post veremos que, para implementar diseños más fieles al problema, debemos cuidar el proceso de creación de interfaces, y evitar dejarnos embaucar por modelos heredados que podrían limitar nuestra visión..&lt;/p&gt;

&lt;p&gt;Para plantear esta idea, usaremos un problema sencillo, estudiando, en primer lugar, un posible modelado que presenta los problemas de diseño que queremos evitar. A continuación, comentaremos un modelado alternativo que mejora el enfoque inicial resolviendo sus problemas.
Modelaremos el recuento de puntos de un partido de tenis, pero centrándonos sólo en el subproblema de conseguir
un punto de set. Partiremos de la siguiente definición:&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;width: 50%;display: block;margin: auto;&quot; src=&quot;/assets/posts/restringiendo-interfaces-ii/scoreboard.png&quot; alt=&quot;Scoreboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Un marcador de tenis se compone de sets, puntos de set, y puntos de juegos. Para ganar un punto de set, hay que jugar varios
puntos de juego. Los jugadores parten de 0-0, cuando un jugador gana un punto se suma 15 al marcador, por ejemplo, 0-15. Una vez llegas a 30, suman
10, es decir, 0-40, y si ese jugador gana el siguiente punto, ganaría el punto de set. En el caso de empatar en 40-40 (denominado Deuce),
se procede a conceder ventajas de juego, por ejemplo Ad.-40. Si el jugador que va por detrás marca otro punto de juego, el marcador regresa a Deuce,
y se volvería a repetir que si algún jugador gana el siguiente punto de juego, se concede una ventaja.
Para ganar el punto de set, se necesita ganar un punto cuando tienes una ventaja, o lo que es lo mismo, se gana con una diferencia de dos puntos
por encima del otro jugador.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Una progresión del marcador de un set válida sería la siguiente:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0-0 -&amp;gt; 0-15 -&amp;gt; 15-15 -&amp;gt; 15-30 -&amp;gt; 30-30 -&amp;gt; 40-30 -&amp;gt; 40-40 -&amp;gt; Ad.-40&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Con esta descripción podríamos empezar a modelar. Como dijimos partiremos de una implementación factible y la iremos transformando poco a poco para exponer las ideas que pretendo explorar en este post. La implementación inicial pertenece
a enunciado de la &lt;a href=&quot;https://github.com/emilybache/Tennis-Refactoring-Kata/tree/main/kotlin&quot;&gt;Kata de refactoring Tennis&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mangelviera/cca261a73dc7595b9f464c1657d5ed6b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Lo que hace este código es llamar al método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wonPoint(playerName)&lt;/code&gt; con el nombre del jugador (o equipo) que marca
el punto y sumarle un punto en el marcador. Luego, el cliente que consume este código, llama al método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; que devuelve la puntuación
con un tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; que representa los puntos de juego en la jerga del tenis.&lt;/p&gt;

&lt;p&gt;A partir de este código podemos analizar qué heurísticas podrían haber llevado a esta implementación. Lo primero que observamos
es que &lt;strong&gt;para determinar los puntos de un jugador, se emplean operaciones aritméticas&lt;/strong&gt;, es decir, cada vez que un jugador gana un punto,se almacena el estado en los campos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore1&lt;/code&gt; o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore2&lt;/code&gt;. Además, &lt;strong&gt;los valores numéricos empleados para operar con los puntos no son los
mismos que se emplean para representar los puntos de juego de un set&lt;/strong&gt;, en su lugar, se usa una serie matemática infinita
de números enteros para calcular la puntuación del jugador.&lt;/p&gt;

&lt;p&gt;Estamos ante un problema típico de implementación, como el  que vimos
en el post anterior: existe un &lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt;, es decir, hay valores en el código que tienen un significado implícito no reflejado en el diseño. Este problema de diseño también lo podríamos haber identificaco mediante otra heurística: los &lt;a href=&quot;https://martinfowler.com/bliki/CodeSmell.html&quot;&gt;Code Smells&lt;/a&gt;. En este caso estaríamos ante un &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;Data Clump&lt;/a&gt;. Los Data Clumps hacen referencia a aquellos datos datos que sólo tienen sentido cuando están juntos, y que de forma implícita se relacionan. Si uno de esos datos cambia, el otro se ve forzado a cambiar conjuntamente. Este ejemplo lo podemos encontrar en la representación de la serie aritmética en los campos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore1&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore2&lt;/code&gt;y el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt;, ambos datos se interrelacionan, pues score necesita conocer la lógica de la progresión de la serie para poder operar con ella y saber cuál es el valor de marcador que tiene que devolver y la serie conoce como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; emplea sus datos para poder identificar el marcador y por tanto, no puede cambiar libremente. Podríamos suavizar este problema de diseño de forma implícita si los números que empleamos en estas operaciones aritméticas fuesen los mismos que usa el problema en su definición (0, 15, 30, 40). Pero nuestro diseño seguiría sin utilizar tipos complejos para representar y forzar que sólo podamos elegir valores correctos, ya que la interfaz actual no restringe qué valores se pueden usar. La definición implícita que generaríamos sólo sería válida si el desarrollador
conoce bien las reglas del tenis, en caso contrario, estaríamos en la casilla de salida, es decir, la solución de limitar los números utilizados en las operaciones aritméticas, no ayudaría a hacer más explícitas las reglas de negocio ni adocumentar el comportamiento del código para facilitar su comprensión.&lt;/p&gt;

&lt;p&gt;El problema que presenta el al método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; se debe a que la elección de representar
los puntos como un entero que sigue una serie en incrementos de uno, fuerza a mantenerlos puntos como estado local para poder determinar el momento del juego en el que se está (es decir, los marcadores entre el 0-0 y Deuce, Advantage y Victoria) y saber si hay algún jugador que va por delante, hay empate o se ha ganado el punto de set. El hecho de que cuando un jugador gana un punto de juego se incremente la serie, obliga a que el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; tenga que absorber el comportamiento del cálculo de puntos y que no tenga exclusivamente su representación.&lt;/p&gt;

&lt;p&gt;Este diseño tiene por tanto dos problemas pronunciados:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Representar los posibles estados del problema con números ajenos a su definición&lt;/strong&gt;. Esto ha complicado el algoritmo que permite obtener los puntos actuales de ambos jugadores &lt;em&gt;agravando el &lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt;.
Los posibles valores de la serie implican que el mismo valor puede significar diferentes cosas según el estado que se encuentre el marcador y a medida que se altere&lt;/em&gt;. Lo que nos lleva al segundo problema.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;La identidad del mismo valor cambia y puede tener un significado distinto, y su &lt;em&gt;”Meaning&lt;/em&gt;”, se superpone a la serie matemática.&lt;/strong&gt; Este tipo de acoplamiento se denomina  &lt;em&gt;&lt;strong&gt;&lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence of Algorithm&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;, que implica que varias partes de nuestro diseño conocen la lógica interna del algoritmo e implícitamente aceptan un contrato sobre la transformación de los datos. Este problema lo encontramos a medida que avance la serie a medida que transcurre el partido. Por ejemplo, pongamos que los jugadores van 40-40 (Deuce), el estado de nuestra clase la primera vez que llegan a esta puntuación es de 3-3. Pero hay diferentes estados de nuestra serie que significan también empate, como por ejemplo: 4-4, 5-5, 99-99… Pero en un marcador de 4-2, el cuatro significa victoria, mientras que en un 4-3, significa ventaja. Por tanto, el mismo valor puede significar hasta cuatro cosas distintas.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;state-machine&quot;&gt;Implementando el rediseño&lt;/h3&gt;

&lt;p&gt;El primer paso y el más barato, en términos de economía de software, es eliminar el tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;playerName&lt;/code&gt; y lo sustituimos por un tipo enumerado que represente
a los dos posibles jugadores (o equipos) que pueden jugar un partido de tenis, &lt;strong&gt;eliminando así el &lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt; del player y a su vez protegiéndonos con el compilador de posibles entradas no válidas&lt;/strong&gt;.
Luego para resolver el problema de la serie emplearemos sólo el rango de valores posibles para los puntos de juego de un partido de tenis.&lt;/p&gt;

&lt;p&gt;Este sería el resultado de nuestra primera transformación:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mangelviera/e07b90e9db63bcc102f3af123c6153e6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;El siguiente paso es reducir la &lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot;&gt;complejidad ciclomática&lt;/a&gt; en el método
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; que calculaba la representación de los puntos de los jugadores. Para conseguirlo, primero, duplicamos el código del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; que contiene.
Y a continuación, hacemos que sólo emplee los valores de los puntos posibles en un juego de tenis mediante un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt;.
Con esto llevamos la lógica del cálculo aritmético al método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wonPoint(Player)&lt;/code&gt;, que ahora es capaz de reflejar, usando estos valores, cómo funciona
un marcador, consiguiendo así centralizar en un único lugar esa responsabilidad En el proceso hemos inventado dos nuevos valores que no pueden soportar una de las lógicas del problema, la &lt;em&gt;ventaja de un jugador&lt;/em&gt; y la &lt;em&gt;victoria&lt;/em&gt;. Esto se debe a que tanto la  ventaja de un jugador como la victoria en el punto
de set no tienen valores numéricos asociados. &lt;strong&gt;Los valores elegidos para representar estos últimos son el 41, para la ventaja de algunos de los jugadores y el 50, para la victoria.&lt;/strong&gt;
El porqué de esta última decisión la podemos entender como un paso intermedio en el refactor. Ahora mismo en el proceso de descubrir nuestro diseño optamos por elegir valores ajenos a la definición del problema para que generen ruido y la necesidad de eliminarlos al final.&lt;/p&gt;

&lt;p&gt;Con este refactor hemos obtenido nuevos aprendizajes sobre el problema:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Los valores de victoria y ventaja no son numéricos, son estados&lt;/strong&gt; que se representan de forma distinta al resto del conjunto de valores numéricos posibles.
La nueva implementación que elimina la serie matemática que almacenaba el estado y que se usaba para calcular quién iba ganando, nos desvela otra perspectiva sobre el diseño. Gracias al marcador de ventaja y la victoria, podemos exponer esta nueva interpretación,
en un Deuce el jugador que gane el siguiente punto y adquiera ventaja (40-Ad.), sólo tiene dos posibles estados siguientes, volver al Deuce o
ganar el punto. Además otro detalle que podemos observar es que existen diferentes combinaciones de puntos desde las que podemos alcanzar la victoria de algún jugador.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Podemos deducir que estamos ante a una máquina de estados finita, lo cual nos permitiría replantear el algoritmo desde otra perspectiva.&lt;/strong&gt;
Si representamos los puntos como transiciones de estado sobre un diagrama de estados tendríamos algo tal que así:&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;state-machine&quot;&gt;Marcador como máquina de estados&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/restringiendo-interfaces-ii/state_machine.png&quot; alt=&quot;tate machine&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tenemos 20 posibles estados dentro de nuestro problema, algo bastante sencillo de modelar y que nos permitiría eliminar las operaciones aritméticas de nuestro código. Representar los puntos mediante valores numéricos nos impedía ver otras opciones de diseño más sencillas con las que plantear el problema y limitar el dominio de posibles valores.&lt;/p&gt;

&lt;h3 id=&quot;simplified-state-machine&quot;&gt;Marcador como máquina de estados simplificada&lt;/h3&gt;

&lt;p&gt;Podemos también emplear una simplificación de la máquina de estados a través de un &lt;a href=&quot;https://es.wikipedia.org/wiki/Aut%C3%B3mata_finito#Generalizaciones_de_aut.C3.B3matas_finitos&quot;&gt;transductor de estados&lt;/a&gt; como la &lt;a href=&quot;https://es.wikipedia.org/wiki/M%C3%A1quina_de_Mealy&quot;&gt;máquina de Mealy&lt;/a&gt; y a partir de las entradas identificar estados que son comunes y que representan a un único estado duplicado múltiples veces. En este caso podemos reducir los 20 estados a un total de 4, Initial, para los valores comprendidos entre el 0-0 y el 40-40, Deuce, para 40-40, Advantage para los marcadores 40-Ad. y Ad.-40 y Win, para cuando un jugador gana la partida, quedando de esta manera:&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;width: 35%;display: block;margin: auto;&quot; src=&quot;/assets/posts/restringiendo-interfaces-ii/state-machine-ii.png&quot; alt=&quot;Simplified state machine&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Un detalle importante es entender que hay múltiples procesos para alcanzar esta solución. En el caso que nos atañe, lo hemos conseguido a través del análisis del estado a partir de los posibles valores del tenis. &lt;strong&gt;Pero si hubiéramos partido del análisis del comportamiento en vez de enfocarnos en los valores, hubiéramos llegado al mismo sitio.&lt;/strong&gt; El  &lt;strong&gt;&lt;a href=&quot;https://refactoring.guru/design-patterns/state&quot;&gt;State Pattern&lt;/a&gt;&lt;/strong&gt; que vamos a emplear para diseñar la nueva solución permite desde el análisis del problema, encontrar el patrón en el problema por las fuerzas y motivaciones detrás del mismo. No es necesaria usar la fuerza bruta para conseguir llegar a la solución que ahora veremos, en este caso he querido que sea así por analizar este caso que me parece curioso, pero es importante no confundir &lt;strong&gt;&lt;em&gt;State Pattern = Máquina de estados finita.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Luego de este análisis, podemos empezar a transformar el código &lt;strong&gt;utilizando el &lt;a href=&quot;https://refactoring.guru/design-patterns/state&quot;&gt;State Pattern&lt;/a&gt;&lt;/strong&gt;. Este patrón nos ayudará a representar los diferentes estados de las máquinas que hemos diseñado a partir del código anterior. También tiene un valor añadido porque solventará el Data Clump del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; y y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore1&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mScore2&lt;/code&gt; en los nuevos objetos que representan el estado. Pero lo más importante es que cada lógica de transición de un estado a otro estará albergada dentro de la lógica de las diferentes clases que surjan en la implementación.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mangelviera/c92e6e54dc9b89a7b96e56a8c07cb3d0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Este código es el que representa la &lt;a href=&quot;/2022/02/restringiendo-interfaces-II-modelando-apariencias#state-machine&quot;&gt;primera máquina de estados&lt;/a&gt;. Esta sería la propuesta inicial de la implementación. Hemos eliminado las operaciones aritméticas y hemos creado el conjunto de transiciones de estados posibles a través de una nueva clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scoreboard&lt;/code&gt; que aglomera la puntuación actual de ambos jugadores y cuando alguno de los dos marca un nuevo punto de juego, se transiciona a otro estado que refleje la victoria de ese jugador. Esta nueva clase absorbe ambos switch de TennisGame y se reemplazan a través del refactor &lt;a href=&quot;https://refactoring.guru/es/replace-conditional-with-polymorphism&quot;&gt;Replace conditional with Polymorphism&lt;/a&gt; que lo elimina de los método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wonPoint(Player)&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si ahora eliminamos la duplicación de estados que hemos dicho anteriormente y representamos la &lt;a href=&quot;/2022/02/restringiendo-interfaces-II-modelando-apariencias#simplified-state-machine&quot;&gt;máquina de estados simplificada&lt;/a&gt; el resultado será el siguiente:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mangelviera/6f00d5e693a770f7f8ca1b6330625f38.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Como se puede observar, la clase ScoreBoard se convierte en interfaz y deja de ser un enumerado, y tenemos diferentes implementaciones de la interfaz en las clases Initial, Deuce, Advantage y Win. Initial absorbe la lógica de transición entre los estados duplicados y es la que avanza de estado una vez se llega a 40-40, que transiciona al estado Deuce. Deuce concederá ventajas avanzando al estado Advantage y este último avanza a Win si un jugador ganó o volverá a Deuce si vuelven a empatar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ambos diseños son inmutables, las transiciones entre estados no producen cambio interno de estado.&lt;/strong&gt; En la primera implementación al ser un enumerado es bastante fácil de ver pues es un enumerado sin estado interno. Pero en el caso de la implementación de la máquina de estados simplificada hay que observar que aunque &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initial&lt;/code&gt;, alberga estado, no lo modifica internamente, &lt;strong&gt;lo que hace es crear un estado nuevo a partir de su propio estado modificado, que puede ser mantenerse en el estado actual o transicionar a otro estado con estos nuevos valores.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusiones&quot;&gt;&lt;strong&gt;Conclusiones&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Como comenté en el post anterior, &lt;strong&gt;la clave de diseñar interfaces no trata sólo de definir interfaces a prueba de errores humanos, sino también hacerlas semánticas.&lt;/strong&gt; Esto lo hemos visto con ambas implementaciones, pues ambas son restrictivas y semánticas.&lt;/p&gt;

&lt;p&gt;En el caso de la Initial, Deuce, Advantage y Win, hemos creado un nuevo término no existente en la jerga para expresar un abstracción subyacente en el modelo, mientras que la otra si que es fiel a la jerga existente. Ambas opciones son perfectamente válidas y &lt;strong&gt;a la hora de elegir el diseño final es tener claros los &lt;em&gt;ejes de cambio&lt;/em&gt; &lt;a href=&quot;https://codesai.com/2018/03/examples-lists-in-tdd&quot;&gt;[1]&lt;/a&gt; &lt;a href=&quot;https://www.thebigbranchtheory.dev/post/single-responsablity/&quot;&gt;[2]&lt;/a&gt; de nuestro sistema.&lt;/strong&gt; En el caso del tenis es sencillo, al ser un problema acotado y definido, podríamos quedarnos con la solución con 20 estados aunque su dominio sea espacialmente mayor por la duplicidad del mismo estado varias veces. La solución de cuatro estados coloca en un sitio más cohesivo la lógica de a qué estado tiene que avanzar. Ante un problema que no fuera de dominio finito preferiría la solución con menos estados ya que su diseño es más fácil evolucionar para satisfacer nuevas necesidades de negocio.  Así que, aquí te dejo elegir la solución que más consideres oportuna para la Kata Tennis, elige tus tradeoffs y como dice &lt;a href=&quot;https://twitter.com/richhickey?lang=es&quot;&gt;Richard Hickey&lt;/a&gt; &lt;em&gt;“Pick your poison”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Es muy valioso que al diseñar intentamos siempre &lt;strong&gt;evaluar desde múltiples heurísticas los problemas que podemos encontrar en nuestros diseños&lt;/strong&gt;. En esta kata concretamente, esta práctica nos ha aportado mucho  porque identificar los diferentes tipos de &lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence (Meaning y Algorithm)&lt;/a&gt;, el &lt;a href=&quot;https://refactoring.guru/es/smells/data-clumps&quot;&gt;code smell Data Clump&lt;/a&gt; y ver que las fuerzas del problema se corresponden con las del &lt;a href=&quot;https://refactoring.guru/design-patterns/state&quot;&gt;patrón estado&lt;/a&gt; ha empujado a nuestro diseño al mismo destino gracias a triangular los mismos síntomas desde diferentes perspectivas o heurísticas. Lo interesante es que en este caso el resultado de aplicar las diferentes heurísticas se reforzaban unas a otras ya que se apuntaban a la misma dirección de diseño.&lt;/p&gt;

&lt;p&gt;Cuando empezamos a definir el ejemplo del juego de tenis encontramos varios elementos que definen el lenguaje del espacio del problema, y surgen
valores o elementos que representan el dominio del mismo. Cuando se nos da un código como el inicial, que toma ciertas decisiones de diseño que resuelven el problema obviando este lenguaje/elementos/dominio,** nos alejamos de encontrar una solución que sea más semántica con el problema y dejamos permear en el diseño detalles de bajo nivel que distraen a quien lo lee.** Emplear únicamente la serie aritmética infinita dejaba exponer un diseño más acorde al tipo de problema que presenta la kata tenis y la primera transformación que hicimos fue seguir asumiendo que el problema era exclusivamente matemático, pues la solución ya lo contemplaba, y los valores posibles dentro del enunciado, a excepción de la ventaja y victoria, eran numéricos.
&lt;strong&gt;Cuando modelamos un problema es necesario mirarlo o tratar de representarlo desde varios prismas, para evitar caer en la trampa de la solución aparente&lt;/strong&gt;. No hay que caer en la trampa de elegir la opción más sencilla de percibir, pero que representa el problema con un diseño más complejo, que escoger la
opción menos aparente, pero que más se adapta al problema. &lt;strong&gt;Pensar en los límites de tus valores de entrada puede ser una heurística que te ayude a acotar el problema y guiarte a modelar tus interfaces correctamente y seguir destilando el problema hasta dar con el diseño que buscas.&lt;/strong&gt; Además es útil conocer y aplicar otras heurísticas, como el connascence, los code smells o los patrones, para contrastar el diseño que vas encontrando.&lt;/p&gt;

&lt;p&gt;Espero que te haya gustado el post y que me des feedback de qué te ha parecido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/books/refactoring.html&quot;&gt;Refactoring&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;. Mencionados en el post: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Refactoring to Polymorphism y Data Clump&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Erich_Gamma&quot;&gt;Erich Gamma&lt;/a&gt;, &lt;a href=&quot;http://software-pattern.org/Author/29&quot;&gt;Ralph Johnson&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Vlissides&quot;&gt;John Vlissides&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?RichardHelm&quot;&gt;Richard Helm&lt;/a&gt;. El mencionado en el post &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State Pattern&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/2017/01/about-connascence&quot;&gt;About Connascence&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/2018/03/examples-lists-in-tdd&quot;&gt;Examples lists in TDD&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.thebigbranchtheory.dev/post/single-responsablity/&quot;&gt;Single Responsibility ¿Principle?&lt;/a&gt;, &lt;a href=&quot;https://www.thebigbranchtheory.dev/&quot;&gt;The Big Branch Theory podcasts&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/bliki/CodeSmell.html&quot;&gt;Code Smells&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://codesai.com/2018/08/hidden-tuples&quot;&gt;Data clumps, primitive obsession and hidden tuples&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://garajeando.blogspot.com/2012/11/refactoring-kata-tennis-to-state-pattern.html&quot;&gt;Refactoring Kata Tennis to State Pattern&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</description>
          <pubDate>2022-02-19T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/02/restringiendo-interfaces-II-modelando-apariencias</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/02/restringiendo-interfaces-II-modelando-apariencias</guid>
        </item>
      
    
      
        <item>
          <title>Notes on LSP from Agile Principles, Practices and Patterns book</title>
          <description>&lt;p&gt;I continue sharing my notes on SOLID to prepare the ground for the upcoming &lt;a href=&quot;https://thebigbranchtheorypodcast.github.io/&quot;&gt;The Big Branch Theory Podcast&lt;/a&gt; episode about Liskov Substitution Principle.&lt;/p&gt;

&lt;p&gt;Ok, so these are the raw notes I took while reading the chapter devoted to &lt;b&gt;Liskov Substitution Principle (LSP)&lt;/b&gt; in &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_Cecil_Martin&quot;&gt;Robert C. Martin&lt;/a&gt;’s &lt;a href=&quot;https://www.goodreads.com/book/show/84983.Agile_Principles_Patterns_and_Practices_in_C_&quot;&gt;Agile Principles, Practices and Patterns in C#&lt;/a&gt; book (I added some personal annotations between brackets):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;“The primary mechanisms behind the OCP are abstraction and polymorphism” &amp;lt;- [but in some languages inheritance is needed to have polymorphism]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;”.. questions addressed by the LSP”&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;“What are the desgin rules that govern this particular use of inheritance hierarchies?”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“What are the characteristics of the best inheritance hierarchies?”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“What are the traps that will cause us to create hierarchies that do not conform to OCP?”&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;LSP -&amp;gt; “Subtypes must be substitutable for their base types”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Violating LSP often results in the use of runtime type checking in a manner that grossly violates OCP”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“a violation of LSP is a latent violation of OCP”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“… more subtle way of violating LSP” -&amp;gt; “.. use of IS-A relationship is sometimes thought to be one of the fundamental techniques of OOA, a term frequently used but seldom defined […]. However this kind of thinking can lead to some subtle yet significant problems. Generally, these problems are not foreseen until we see them in code”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Invariants -&amp;gt; “those properties that must always be true regardless of state”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“… when the creation of a derived class causes us to make changes to the base class, it often implies that the design is faulty”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Validity is not intrinsic”&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;“LSP leads us to a very important conclusion: &lt;b&gt;A model, viewed in isolation, cannot be meaningfully validated. The validity of a model can be expressed only in terms of its clients.&lt;/b&gt;”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“When considering whether a particular design is appropriate, one cannot simply view the solution in isolation. One must view it in terms of the reasonable assumptions made by the users of that design”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“Therefore, as with all other principles, it is often best to defer all but the most obvious LSP violations until the related fragility has been smelled”&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“IS-A is about behavior” -&amp;gt; “… &lt;b&gt;it is behavior that software is really all about&lt;/b&gt;. &lt;b&gt;LSP makes it clear than in OOD, the IS-A relationship pertains to behavior that can be reasonably assumed and that clients depend on&lt;/b&gt;” &amp;lt;- [related to behavioural approach to modelling shown in &lt;a href=&quot;http://davewest.us/&quot;&gt;David West&lt;/a&gt;’s &lt;a href=&quot;https://www.goodreads.com/book/show/43940.Object_Thinking&quot;&gt;Object Thinking&lt;/a&gt;, or &lt;a href=&quot;https://en.wikipedia.org/wiki/Rebecca_Wirfs-Brock&quot;&gt;Rebecca Wirfs-Brock&lt;/a&gt;’s &lt;a href=&quot;https://www.goodreads.com/book/show/1887814.Designing_Object_Oriented_Software&quot;&gt;Designing Object-Oriented Software]&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“How do you know what your clients will really expect? There is a technique for making those reasonable assumptions explicit and thereby enforcing LSP…” -&amp;gt; &lt;a href=&quot;https://wiki.c2.com/?DesignByContract&quot;&gt; Design By Contract (DBC)&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;b&gt;“Using DBC, the author of a class explicitly states the contract of that class. The contract informs the author of any client code if the behaviors that can be relied on. The contract is specified by declaring preconditions and postconditions for each method. The preconditions must be true for the method to execute. On completion, the method guarantees that the postconditions are true.”&lt;/b&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“…the rule for preconditions and postconditions of derivatives, as stated by &lt;a href=&quot;https://en.wikipedia.org/wiki/Bertrand_Meyer&quot;&gt;Meyer&lt;/a&gt;, is: &lt;b&gt;‘A routine redeclaration [in a derivative] may only replace the original precondition by one equal or weaker, and the original postcondition by one equal or stronger’”&lt;/b&gt; &amp;lt;- “X is weaker than Y if X does not enforce all the constraints of Y. It does not matter how many new constraints X enforces”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“In other words, when using an object through its base class interface, &lt;b&gt;the user knows only the preconditions and postconditions of the base class&lt;/b&gt;. Thus, derived objects must not expect such users to obey preconditions that are stronger than those required by the base class. Also, derived classes must conform to all the postconditions of the base. That is, their behaviors and outputs must not violate any of the constraints established for the base class.” “&lt;b&gt;Users of the base class must not be confused by the output of the derived class.&lt;/b&gt;” &amp;lt;- [a form of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Principle_of_least_astonishment&quot;&gt;Least Astonishment Principle&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Contracts can […] be specified by writing unit tests. By thoroughly testing the behavior of a class, the unit tests make the behavior of the class clear. Authors of the client code will want to review the unit tests in order to know what to reasonably assume about the classes they are using”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“It’s a big advantage not to have to know or care what kind of [sth] you are using. It means that the programmer can decide which kind of [sth] is needed in each particular instance, and none of the client functions will be affected by that decision”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“…the problem with conventions: they have to be continually resold to each developer”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“There are occasions when it is more expedient to accept a subtle flaw in polymorphic behavior than to attempt to manipulate the design into complete LSP compliance. &lt;b&gt;Accepting compromise instead of pursuing perfection is an engineering trade-off. A good engineer learns when compromise is more profitable that perfection.&lt;/b&gt; &lt;b&gt;However, conformance to LSP should not be surrendered lightly. The guarantee that a subclass will always work where its base classes are used is a powerful way to manage complexity. Once it is forsaken we must consider each subclass individually.&lt;/b&gt;”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Factoring is a powerfull tool. If qualities can be factored out of two subclassses, there is the distinct possibility that other classes will show up later that need those qualities too”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“&lt;a href=&quot;https://en.wikipedia.org/wiki/Rebecca_Wirfs-Brock&quot;&gt;Rebecca Wirfs-Brock&lt;/a&gt;, on factoring:”&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;b&gt;“We can state that if a set of classes all support a common responsibility, they should inherit that responsibility from a common superclass”&lt;/b&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;b&gt;“If a common superclass does not already exist, create one, and move the common responsibility to it. After all such a class is demonstrably useful […]. Isn’t it conceivable that a later extension of your system might add a new subclass that will support those same responsibilitties in a new way? This new superclass will probably be an abstract class”&lt;/b&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Some simple heuristics can give you some clues about LSP violations. These heuristics all have to do with derivative classes that somehow remove functionality from their base class. A derivative that does less that its base is usually not substitutable for that base and therefore violates LSP” &amp;lt;- “The presence of degenerate functions in derivatives is not always indicative of an LSP violation, but it’s worth looking at them when they occur” [see &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=21&quot;&gt;Refused Bequest code smell&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;b&gt;“The OCP is at the heart of many of the claims made for OOD. […] The LSP is one of the prime enablers of OCP”&lt;/b&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;b&gt;“The substitutability of subtypes allows a module, expressed in terms of a base type, to be extensible without modification. That substitutability must be sth that developers can depend on implicitly. Thus, the contract of the base type has to be well and prominently understood, if not explicitly enforced, by the code”&lt;/b&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“The […] IS-A is too broad to act as a definition of a subtype. The true definition of a subtype is substitutable, where &lt;b&gt;substitutability is defined by either an explicit or implicit contract&lt;/b&gt;”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.pexels.com/es-es/@padrinan?utm_content=attributionCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=pexels&quot;&gt;Foto de Miguel Á. Padriñán en Pexels&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2022-02-14T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/02/notes-on-lsp</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/02/notes-on-lsp</guid>
        </item>
      
    
      
        <item>
          <title>Mutando para simplificar</title>
          <description>&lt;p&gt;Una de las herramientas que mencionamos en &lt;a href=&quot;https://codesai.com/curso-de-tdd/&quot;&gt;nuestro curso de TDD&lt;/a&gt; es &lt;a href=&quot;https://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;mutation testing&lt;/a&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. Para quien no esté familiarizado, es una herramienta que, en líneas generales, lanza nuestra batería de tests haciendo modificaciones (mutaciones) del código de producción que introducen defectos. Si un test falla, significa que nuestros tests protegen contra el defecto introducido (o en términos de mutation testing, nuestros tests matan al mutante). En cambio, si todos los tests pasan, significa que los tests no protegían contra el defecto introducido.&lt;/p&gt;

&lt;p&gt;Personalmente, el mutation testing no es algo que use a diario, pero sí que es valioso conocer su existencia si te encuentras en el caso de que necesitas cambiar una zona de código sensible en la que un bug supondría perder mucho dinero.&lt;/p&gt;

&lt;p&gt;Un ejemplo muy sencillo que puede servir para mostrar su potencia es cuando estamos haciendo comprobaciones de rangos de números. Por ejemplo, en la &lt;a href=&quot;https://codesai.com/2016/05/ohce-kata&quot;&gt;kata ohce&lt;/a&gt; hay una parte de la funcionalidad que saluda de diferentes maneras según la hora del día:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Entre las 20 y las 6, ohce te dirá ¡Buenas noches!&lt;/li&gt;
  &lt;li&gt;Entre las 6 y las 12, ohce dirá ¡Buenos días!&lt;/li&gt;
  &lt;li&gt;Entre las 12 y las 20, dirá ¡Buenas tardes!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si no tenemos cuidado al testear estos rangos, podemos acabar con una batería de tests en verde que pruebe que si son las 8 te dice ¡Buenos días!, si son las 14 te responde ¡Buenas tardes! y a las 23 ¡Buenas noches!. Con estos tres casos, tendremos los tests en verde y 100% de cobertura, genial, ¿verdad?&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/9f108ff5334bcf79734621b9f3045230.js?file=naive-tests.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/9f108ff5334bcf79734621b9f3045230.js?file=greetings-sorted.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;seguridad-infundada&quot;&gt;Seguridad infundada&lt;/h2&gt;

&lt;p&gt;Si ejecutasemos una herramienta de mutation testing como &lt;a href=&quot;https://stryker-mutator.io/docs/stryker-js/introduction/&quot;&gt;Stryker&lt;/a&gt;, nos encontraríamos la sorpresa de que 6 mutaciones en nuestro código sobrevivirían a los casos de prueba que tenemos definidos ahora mismo.&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 75%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-02-mutation-testing/mutant-survived.png&quot; alt=&quot;Mutaciones supervivientes en una línea de código&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Mutaciones supervivientes en una línea de código&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;En la figura de arriba podemos ver una sección del informe que genera Stryker. Nos está marcando que en ese if ha hecho 3 mutaciones que han sobrevivido, siendo una de ellas el cambiar un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;=&lt;/code&gt; por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt;. ¿Por qué ha pasado esto? Porque nuestros tests solamente estaban fijando un valor en el interior del rango, el número 8, y no sus extremos.&lt;/p&gt;

&lt;p&gt;Si cambiamos los tests de forma que fijen los extremos de los rangos y volvemos a ejecutar Stryker, comprobaremos que no sobrevivirá ninguna mutación.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/9f108ff5334bcf79734621b9f3045230.js?file=tests.js&quot;&gt;&lt;/script&gt;

&lt;figure style=&quot;margin:auto; width: 75%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-02-mutation-testing/mutants-killed.png&quot; alt=&quot;Informe de Stryker por consola mostrando 0 mutaciones supervivientes&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Informe de Stryker por consola mostrando 0 mutaciones supervivientes&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;simplificando-nuestro-código&quot;&gt;Simplificando nuestro código&lt;/h2&gt;

&lt;p&gt;Hasta ahora hemos visto cómo mutation testing nos puede ayudar a encontrar aquellos tests que hemos olvidado hacer. Ahora me gustaría hablar de un caso particular que nos encontramos recientemente en una sesión de &lt;a href=&quot;https://twitter.com/codesaidev/status/1485585588933771264&quot;&gt;práctica deliberada con la gente de Audiense&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cuando una de las parejas estaba usando mutation testing para comprobar que habían hecho todos los tests necesarios para cuadrar el rango de horas, esperábamos encontrar una lista de mutantes parecida a la que aparece en la figura de más arriba.  Sin embargo, nos encontramos con que había sobrevivido un único mutante:&lt;/p&gt;

&lt;figure style=&quot;margin:auto; width: 75%&quot;&gt;
&lt;img src=&quot;/assets/posts/2022-02-mutation-testing/mutant-remove-condition.png&quot; alt=&quot;Mutación de Stryker que sobrevive borrando una condición&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Mutación de Stryker que sobrevive borrando una condición&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Resulta que la condición de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hour &amp;gt;= 6&lt;/code&gt; era innecesaria, ya que la mutación introducida al cambiar dicho código por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; sobrevivía (los tests seguían pasando). Pero revisamos los tests y estaban “bien” así que, ¿qué está pasando?&lt;/p&gt;

&lt;p&gt;Si nos paramos a pensar un poco, debido a cómo están estructurados los ifs, entraremos en el primer caso si la hora es mayor igual que 20 o menor que 6. Si esta condición es falsa, significa que la hora es menor que 20 y mayor o igual que 6, así que la condición que tenemos de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hour &amp;gt;= 6&lt;/code&gt; siempre va a ser true.&lt;/p&gt;

&lt;p&gt;Sabiendo esto, podemos decidir “simplficar” el código y dejar la condición en el segundo if simplemente como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hour &amp;lt; 12&lt;/code&gt;. Cabría preguntarse si este cambio merece la pena o no. A mi de entrada me pareció buena idea, todo lo que sea borrar código siempre me parece bien. El código quedaría así:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/9f108ff5334bcf79734621b9f3045230.js?file=greeting-simplified.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Sin embargo, el código resultante no será fácil de entender para la gente que tendrá que mantenerlo. Aunque podríamos sacar funciones privadas para mejorar su comprensión de las condiciones de los ifs, hemos hecho que el orden de ejecución de los ifs sea importante. Imaginemos que alguien modifica el orden de las comprobaciones. Si el if de los “Buenos días” lo pusiéramos el primero, romperíamos los tests, porque haríamos que para las 4 de la mañana diga Buenas noches en lugar de Buenos días&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para evitar estos problemas seguramente decidiría no borrar la condición innecesaria e ignorar el mutante que ha sobrevivido. Otra opción podría ser refactorizar el código para que los ifs estén en el mismo orden que vimos en la primera solución de la kata, lo cual, no dejaría sobrevivir a ningún mutante.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h2&gt;

&lt;p&gt;Como hemos visto, mutation testing es una herramienta muy útil que nos puede ayudar a encontrar tests que se nos han olvidado y asegurar más nuestro código en las zonas más críticas. Configurarlo para nuestro proyecto es relativamente sencillo (al menos ese es el caso con Stryker en Javascript o PIT en Java), pero tenemos que saber interpretar los datos que nos da y decidir si debemos añadir tests, o bien modificar nuestro código para que mate todas las mutaciones sin perder legibilidad.&lt;/p&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos&lt;/h2&gt;

&lt;p&gt;Me gustaría agradecer a mi compañero &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt; por invitarme a impartir varias sesiones de práctica deliberada con él donde me pude encontrar con este caso, y a la gente de Audiense por su asistencia, especialmente a &lt;a href=&quot;https://twitter.com/ivanportillo11&quot;&gt;Iván Portillo&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/Rober_Segura&quot;&gt;Roberto Segura&lt;/a&gt; porque fue con ellos con quién vimos este curioso caso de mutation testing. Y por último, gracias a mis compañeros de Codesai por el feedback en este post.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] En este &lt;a href=&quot;https://codesai.com/2019/05/killing-mutants-to-improve-tests&quot;&gt;otro post&lt;/a&gt; hablamos también de mutation testing para el desarrollo de la librería &lt;a href=&quot;https://github.com/trovit/reffects&quot;&gt;reffects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] En el informe aparece un timeout porque en el código de la kata hay un bucle que al cambiar una condición se convierte en un bucle infinito y los tests no terminan de ejecutarse.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Aquí tendríamos un ejemplo de &lt;a href=&quot;https://codesai.com/2017/01/about-connascence#3-forms-of-connascence&quot;&gt;Connascence of Execution&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2022-02-11T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/02/mutation-testing</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/02/mutation-testing</guid>
        </item>
      
    
      
        <item>
          <title>Restringiendo interfaces</title>
          <description>&lt;p&gt;Una heurística que empleo para diseñar software, y considero fundamental a la hora de crear interfaces
o APIs claras y orientadas al negocio, es restringir con tipos los errores que podemos introducir en nuestro
diseño al consumir estas APIs dentro de nuestro propio sistema o al ofrecerlas como parte de una librería externa.&lt;/p&gt;

&lt;p&gt;En este post hablaré sobre cómo limitar tus interfaces de esta manera facilita su consumo. Además intentaré ejemplificar
explicando mis preferencias a la hora de cómo modelar un problema de negocio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; El ejemplo trata de ser didáctico, pero no muy alejado de la realidad, se establece un caso de uso simple pero factible
para intentar establecer mi argumento sin tener que extenderme demasiado con detalles del problema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Imaginemos que tenemos una startup que quiere ofrecer a sus usuarios la posibilidad de crear recordatorios para el día de hoy,
Estos recordatorios se componen de cuatro opciones que damos a elegir. La hora del día que quiere que se le recuerde,
los minutos en intervalos de 15 min en esa hora que ha elegido (es decir, 00:00, 00:15, 00:30, 00:45), el mensaje que
quiere que se le recuerde y además la prioridad que tiene ese recordatorio si el usuario tiene varios en esa misma hora y
en el mismo intervalo de minutos para dar más prioridad en cómo queremos que se le notifique al usuario los recordatorios que tiene
y el orden que les aparece.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Una posible implementación de este API podría ser la siguiente:
&lt;script src=&quot;https://gist.github.com/mangelviera/be7ced5279503f2b88e386d2d5a38c41.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Como se ve, hemos indicado todos los parámetros necesarios para que el usuario pueda registrar las necesidades que podría
tener al usar nuestra aplicación para crear recordatorios en el mismo día.&lt;/p&gt;

&lt;p&gt;Una posible implementación de este método, podría ser la siguiente:
&lt;script src=&quot;https://gist.github.com/mangelviera/966282da69ec2f26ad547b210ad88382.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Ahora, para prevenir los posibles errores que podríamos introducir usando esta  API, podemos controlar los parámetros que
le llegan al método haciendo que, por ejemplo, no se pueda dar el caso de crear un recordatorio que sea a las 25:62.
Además, también queremos que el usuario disponga de tres niveles de prioridad para sus recordatorios. Para
resolver este problema podríamos hacer lo siguiente:
&lt;script src=&quot;https://gist.github.com/mangelviera/e9caf7addcb9b9306cd9f79f1ea8326b.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;En esta última implementación he utilizado &lt;a href=&quot;https://en.wikipedia.org/wiki/Defensive_programming&quot;&gt;Defensive Programming&lt;/a&gt;
con el objetivo de evitar la introducción de valores erróneos pero admitidos por el tipo que se usa en la interfaz
(las horas de un día por ejemplo).&lt;/p&gt;

&lt;p&gt;Con esta implementación, nos sería suficiente para establecer la idea que quiero transmitir. Normalmente cuando diseñamos
software, casi de forma automática, empleamos tipos básicos del lenguaje, para modelar las reglas de negocio. 
Esto tiene un problema de que no estamos haciendo explícitos los posibles valores que pueden pasar los que consumen nuestras APIs. 
&lt;strong&gt;Una buena interfaz es aquella que, aparte de ser semántica, limita los errores que puedo cometer cuando trato de usarla&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El interfaz del API que hemos creado tiene un problema de diseño muy claro, nos permite llamar a nuestros métodos con valores
incorrectos y además, el rango de posibles valores incorrectos es mucho más grande que el de valores correctos, es decir, 
si usamos el tipo Integer para representar horas y minutos tenemos casi 4,3 millones de valores posibles frente a tan sólo 24 valores correctos para las horas,
60 para los minutos y 3 para la prioridad. &lt;strong&gt;Estamos eligiendo un diseño de interfaz en el que es mucho
más probable fallar que acertar a la hora de pasar un valor como parámetro&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Este diseño sufre del &lt;a href=&quot;https://refactoring.guru/es/refactoring/smells&quot;&gt;Code Smell&lt;/a&gt;, &lt;a href=&quot;https://refactoring.guru/es/smells/primitive-obsession&quot;&gt;Primitive Obsession&lt;/a&gt;
y que es básicamente la razón de este post&lt;/strong&gt;. Aparte del tema de la elección de horas y minutos, este problema también lo sufre
el parámetro prioridad. Con el entero que representa este valor, no podemos saber si la prioridad es ascendente
o descendente (si el cero es el más prioritario o lo es el tres). 
Lo que nos hace darnos cuenta que el verdadero problema que subyace en este diseño &lt;strong&gt;es un &lt;a href=&quot;https://codesai.com/2017/01/about-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt;
que implica que varios puntos de nuestro diseño tienen que conocer un acuerdo implícito sobre lo que significan esos valores&lt;/strong&gt;.
También es algo que puede suceder con las horas y minutos, porque podríamos decidir no usar el estándar 00:00-23:59,
y usar el de 12:00AM-12:00PM, pero partamos desde el primer estándar como consenso para facilitar el ejemplo.&lt;/p&gt;

&lt;p&gt;Para plasmar cómo restringir las interfaces pueden facilitar el consumo de las mismas, refactoricemos la interfaz, 
creando tipos que representan las posibles opciones válidas que, esto permite, eliminar las elecciones erróneas de quienes usen nuestra interfaz.
&lt;script src=&quot;https://gist.github.com/mangelviera/2e526b46985253d211e135d07388284a.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Nuestros tipos representan las 24 horas de un día, las cuatro elecciones de minutos que mencionamos antes, y las posibles
prioridades que puede elegir el usuario y le damos además semántica, dejando claro cual es la prioridad más alta y la más baja.&lt;/p&gt;

&lt;p&gt;Esto nos permite hacer los siguientes cambios en nuestro código:
&lt;script src=&quot;https://gist.github.com/mangelviera/824b76e64bbdb1742c082912f757f9ff.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Gracias a estos tipos, eliminamos la programación defensiva&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; antes mencionada, y además dejamos claro a nuestros consumidores
cuáles son las opciones disponibles que tiene para usar nuestra API para crear recordatorios y dejar de transportar
números con convenciones implícitas que debemos conocer antes de usarlos por todas las capas de nuestro dominio.&lt;/p&gt;

&lt;p&gt;Otra serie de ventajas de elegir este tipo de diseño:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;El feedback es el más inmediato posible&lt;/strong&gt;. El compilador es una herramienta que muchas veces se ve como una molestia
en vez de un recurso más con el que poder diseñar interfaces más robustas y explícitas. El diseño propuesto, ofrece feedback
sobre la implementación en el momento más prematuro, &lt;strong&gt;cuando hacemos compilar el código&lt;/strong&gt;, este te fuerza a usar
única y exclusivamente las posibilidades correctas a la hora de elegir los parámetros al consumir interfaz. Además como este
feedback es previo a la ejecución de los tests, no es necesario validar esta parte de tu diseño porque el consumidor no tiene
capacidad de saltarse esta barrera de tu AP. Por lo tanto los tests validan únicamente la lógica de negocio, y te ahorras el
tener que testear los límites de tus interfaces, pues ya has forzado esa decisión en los tipos que recibe.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fuerza la transformación de los tipos básicos que vienen de los mecanismos de entrega a un mayor nivel de abstracción&lt;/strong&gt;.
En un diseño de tipo arquitectura hexagonal, diseñar tipos de esta manera fuerza a concentrar la lógica de transformación a los
mismos en las capas más externas de la arquitectura, como en los Controllers o Mappers que residen fuera de la capa de dominio.
Evitamos así que se filtren estos tipos básicos a las capas más internas de nuestro diseño.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Los tipos/objetos funcionan como behaviour attractors&lt;/strong&gt;. Las abstracciones que hemos creado para representar nuestro
modelo de dominio actúan como elementos que atraen comportamiento asociado al propio tipo. Esto favorece la cohesión y reduce
el acoplamiento de otros elementos de nuestro diseño que de otra manera tendrían que conocer el significado de esos tipos y a cómo operar con ellos. Eliminando
el &lt;a href=&quot;https://codesai.com/2017/01/about-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt; (Feature Envy y/o Data Clump) 
suelen aparecer dos smells relacionados &lt;a href=&quot;https://refactoring.guru/es/smells/feature-envy&quot;&gt;Feature Envy&lt;/a&gt; (la atracción de comportamiento a la que nos referimos) y Data Class,
que eliminamos convirtiendo las estructuras de datos en objetos al darles responsabilidades.
Por ejemplo, si le damos una vuelta más al refactor y creamos una clase para los recordatorios tal que así:
&lt;script src=&quot;https://gist.github.com/mangelviera/bee9e1ffd519f6c7f14914da244dd6b9.js&quot;&gt;&lt;/script&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se puede apreciar que hemos conseguido mover la comprobación del mensaje dentro de la clase Reminder, lo cual, si no cumple
la regla de negocio que impide crear recordatorios sin mensaje, ni siquiera inicializa el objeto. Por lo que
una vez más estamos forzando que nuestra API no pueda recibir tipos inválidos, en este caso, gracias a Kotlin,
el compilador fuerza a que si el tipo que ha devuelto el método &lt;em&gt;create&lt;/em&gt; (Reminder?) al poder ser nulo no se le pueda pasar
directamente al &lt;em&gt;setReminder&lt;/em&gt; que solo recibe Reminder no nulos por lo que hay que controlar esta nulabilidad para poder llamarlo,
y forzamos a que el consumidor de nuestra API sea consciente de esta restricción de diseño que hemos creado a partir de la regla de negocio.&lt;/p&gt;

&lt;p&gt;Este es un ejemplo muy claro de atracción de comportamiento, y además es una tendencia bastante fácil de seguir, puesto que
si se diera el caso de que no queremos permitir que se creen recordatorios con palabras que pertenecen a un conjunto de palabras
prohibidas, como por ejemplo insultos, es bastante probable que acabaran en el mismo punto y así cada vez que tengamos reglas de
no permitir crear recordatorios en base a las necesidades de negocio.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aclaro también que seguramente el nulo no sería mi diseño final, pero me parece un ejemplo good enough para ilustrar el concepto de restringir interfaces.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gran parte de la solución de este diseño está asociada al uso de lenguajes con tipado estático en tiempo de compilación&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;,
tiene una razón clara, creo que los tipos con estos lenguajes ayudan a modelar dominios ricos y la forma en la que obtenemos
feedback de nuestro diseño creando restricciones con el compilador. Es probable que incluso carácteristicas como el tipo
nullable de Kotlin no esté en la mayoría de lenguajes, pero me parece una forma de permitir entender una máxima que tengo
a la hora de escribir código, que es expresar mi intención a la hora de diseñar interfaces y hacerlas robustas y limpias.&lt;/p&gt;

&lt;p&gt;Aún así creo que se le puede sacar mucho partido a esta forma de diseñarinterfaces  y que sirva sobre todo para tratar
de evitar leaks de tipos básicos en nuestros diseños. Con ello reducimos el Connasence of Meaning, que es un verdadero dolor para
mí cuando me enfrento a legacy, y más aún si ese legacy ya ni siquiera tiene a su creador en el equipo y tienes que descubrir
para qué sirve y qué significa ese valor que se usó.&lt;/p&gt;

&lt;p&gt;Ojalá que estas ideas puedan influenciar de manera positiva tus diseños en el futuro y que te permitan crear mejores interfaces.
Me gustaría hacer otro post relacionado con esta misma idea, pero, no solamente desde el punto de vista de los consumidores,
sino desde un punto de vista interno y de modelar el negocio con tipos. Esta es una guerra mental que también libro a la hora de desarrollar tipos explícitos
y restrictivos para modelar un problema.&lt;/p&gt;

&lt;p&gt;¡Muchas gracias y espero tu feedback!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] La programación defensiva no deja de existir en nuestro código aunque restrinjamos nuestras interfaces.
                           Lo que provocamos es empujarlas a capas superiores de nuestro diseño, logrando que estas comprobaciones y se hagan antes de que nuestro diseño se deje permear por tipos más básicos.
                           En situaciones en las que nuestro diseño envuelva un tipo primitivo para operar internarmente, lo que puede suceder es que empujemos a los constructores de la clase estas comprobaciones.
                           Eliminando duplicidad de nuestro diseño y impidiendo que se puedan crear objetos que no cumplan las reglas de negocio que ese tipo trata de representar. 
&lt;/div&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Aclaro que no es una ventaja únicamente de los lenguajes de tipado estático, en lenguajes dinámicos es también una restricción
                           muy interesante que con el uso de tests de contrato de interfaces pueden facilitar mucho su uso y que sean una referencia
                           documental a la hora de poder consumirlos.
&lt;/div&gt;

</description>
          <pubDate>2022-01-31T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/01/restringiendo-interfaces</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/01/restringiendo-interfaces</guid>
        </item>
      
    
      
        <item>
          <title>Huyendo de las ramas</title>
          <description>&lt;p&gt;El pasado mes de diciembre, mi compañero &lt;a href=&quot;https://twitter.com/AlfredoCasado&quot;&gt;Alfredo&lt;/a&gt; y yo tuvimos el placer de compartir un par de horas con el &lt;a href=&quot;https://twitter.com/borillo/status/1471972609113956352&quot;&gt;equipo de Declarando&lt;/a&gt; para hablar sobre feature branching, continuous integration, continuous delivery y algunas técnicas como feature flags y cambio en paralelo.&lt;/p&gt;

&lt;p&gt;Hace unos años dimos una &lt;a href=&quot;https://www.youtube.com/watch?v=L5S9b7AdZC8&quot;&gt;charla parecida en la Conferencia Agile Spain&lt;/a&gt;, y me gustaría compartir por aquí algunas ideas sobre cómo hacemos integración continua y por qué nos gusta trabajar así.&lt;/p&gt;

&lt;h2 id=&quot;gitflow&quot;&gt;Gitflow&lt;/h2&gt;

&lt;p&gt;Cuando empecé mi carrera en el mundo del desarrollo, en todos los proyectos que trabajé me tocó trabajar haciendo &lt;a href=&quot;https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow&quot;&gt;Gitflow&lt;/a&gt; o variantes similares. Siendo algo tan común en muchas empresas, pensaría que es algo sencillo pero, viendo el flujo de trabajo, la verdad que no lo parece.&lt;/p&gt;

&lt;figure style=&quot;max-width:360px; margin:auto;&quot;&gt;
    &lt;img src=&quot;https://nvie.com/img/git-model@2x.png&quot; alt=&quot;Gitflow diagram&quot; /&gt;
    &lt;figcaption&gt;&lt;em&gt;From https://nvie.com/posts/a-successful-git-branching-model/&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;No voy a explicar en profundidad el flujo de trabajo con Gitflow, pero sí que hay un detalle que salió cuando tuvimos la charla con el equipo de Declarando y que me resultó muy llamativo.&lt;/p&gt;

&lt;p&gt;La rama master (o &lt;a href=&quot;https://sfconservancy.org/news/2020/jun/23/gitbranchname/&quot;&gt;main&lt;/a&gt; como solemos llamarla hoy en día) es la que se despliega a producción, y vemos que hay 2 formas de llegar a master: mediante una rama de hotfix o mediante una rama de release. Viendo sólo la figura de arriba, se ve que introducir código a master desde un hotfix es más “rápido” (hay menos ceremonias de commits y ramas) que entrar a través de release. La gente de Declarando nos decía “es que a veces la gente de producto viene con una historia de usuario y nos la quiere colar como un hotfix”. Eso también me ha pasado a mi en algún trabajo pero veámoslo desde la perspectiva de alguien de producto que no tiene porqué entender Gitflow. Yo quiero una feature, hay una forma “lenta” de tenerla en producción y una forma “rápida”. ¿Cuál quiero yo? Pues la rápida, obviamente.&lt;/p&gt;

&lt;p&gt;Aparte de la anécdota, ¿tiene sentido tener dos formas de llegar a producción?&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; ¿Por qué aceptamos tener una forma lenta de desplegar si podemos hacerlo de forma más rápida? ¿O es que elegimos hacer un despliegue de forma menos segura para arreglar un problema en producción?&lt;/p&gt;

&lt;h2 id=&quot;incertidumbre-e-inventario&quot;&gt;Incertidumbre e inventario&lt;/h2&gt;

&lt;p&gt;Has estado una semana trabajando tranquilamente en tu rama y anuncias en la daily que la feature está terminada, pero es mentira porque has dejado para el final la integración de tu rama con la rama principal del proyecto. En ocasiones tendrás suerte y será fácil, y otras veces te tocará resolver un conflicto que te llevará media mañana. Además, como resolver el conflicto te ha parecido molesto la próxima vez intentarás tocar el mínimo código posible para evitar conflictos. A partir de  ese momento habrás perdido el refactor oportunista&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;, aquel que hacemos a modo de scout dejando el código por el que pasamos mejor de lo que estaba, ya que ahora no quieres modificar el código por miedo a tener que resolver conflictos.&lt;/p&gt;

&lt;p&gt;En términos de &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development&quot;&gt;Lean&lt;/a&gt;, podemos entender el trabajar en una rama como una optimización local (trabajar en una rama sin que nos molesten es más cómodo que traer cambios de todo el equipo a menudo), pero desde el punto de vista global no es la forma más óptima porque retrasamos el aprendizaje de integrar. Además, el código que está en una rama es inventario, stock que hemos producido y dejado sin entregar, retrasando el valor.&lt;/p&gt;

&lt;h2 id=&quot;feedback-y-pull-requests&quot;&gt;Feedback y pull requests&lt;/h2&gt;

&lt;p&gt;¿Y cómo se suelen llevar los cambios de una rama a main? Normalmente a través de pull requests que bloquean el merge de la rama hasta que X personas lo aprueban.
Los pull requests pueden ser una herramienta muy chula para compartir conocimiento y debatir cómo se desarrolla una solución en equipos que cumplen alguna de estas condiciones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Están distribuidos en distintas zonas horarias o geográficas. El aumento del trabajo en remoto debido a la pandemia nos ha permitido mejorar en cómo hacemos pairing sin estar en una misma oficina, pero compartir conocimiento de forma síncrona con gente que está a muchas horas de diferencia puede ser un problema.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Tiene integrantes con dedicación asimétrica. Cuando hablamos de equipos asimétricos nos referimos a aquellos en los que existen distintos roles con grandes diferencias de dedicación al proyecto. Por ejemplo, en proyectos open source tenemos gente que actúa como maintainers (gente que tiene una visión global del proyecto) y contributos (personas que hacen alguna contribución ocasional para arreglar bugs o añadir pequeñas features).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En una empresa en la que el equipo no está distribuido (o está distribuido pero en zonas horarias cercanas) los pull requests son una manera de revisar código mucho más compleja que hacer pairing o mostrar los cambios al resto del equipo en una mini reunión. ¿Por qué? Imaginemos un equipo de 4 personas, donde cada persona empieza una tarea en una rama. Cuando la primera persona acaba su tarea, hace una pull request y pide al resto de compañeras que revise para poder hacer merge. El resto del equipo está ocupado, así que empezamos una tarea nueva mientras esperamos su feedback. Una de las personas se libera y empieza a revisar el código, pero resulta que el pull request tiene 100 cambios, así que lo mira en diagonal y le da el ok. Al día siguiente, otro miembro del equipo revisa la pull request con más detenimiento y anota 10 comentarios. El desarrollador que hizo la tarea inicialmente recibe una notificación con los comentarios, deja de trabajar en la tarea con la que estaba y lee los comentarios intentando recordar por qué hizo las cosas de esa manera. Así hasta que todo el equipo lo ve ok y se hace merge del pull request. Y mientras tanto la gente de producto esperando que nos pongamos de acuerdo en cómo llamar a una variable en una tarea supuestamente “terminada”.&lt;/p&gt;

&lt;p&gt;¿Qué problemas vemos aquí?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cambios de contexto continuos.&lt;/strong&gt; Cada vez que hay que revisar una pull request, alguien tiene que parar lo que está haciendo (o hacerlo en un rato muerto, como después de comer) y revisarlo. Cuando llega el feedback, quien hizo el pull request tiene que parar lo que está haciendo y hacer memoria para poder discutir el tema.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Bloqueo en la entrega de valor.&lt;/strong&gt; No estoy cuestionando que nos preocupemos por los nombres de las cosas y por el diseño de nuestro software, lo que propongo es que si ya hemos solucionado un problema y está funcionando, entreguemos el valor. Luego habrá tiempo de discutir sobre él, refactorizar o incluso borrar el código si hemos visto que no aporta el valor que esperábamos.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mejora-contínua-conoce-tu-contexto&quot;&gt;Mejora contínua, conoce tu contexto&lt;/h2&gt;

&lt;p&gt;Con este post no quiero que te vayas con la idea de “tengo que hacer trunk based development”. Es importante siempre conocer la teoría, practicar las técnicas en cosas que tengan poco riesgo (de esto hablaremos en otros posts) y, si encaja en tu contexto, dar el salto. Al final lo importante es cuestionar siempre lo que hacemos. No decir “es que en la empresa siempre hemos hecho gitflow”, sino pararte a pensar, detectar posibles problemas y encontrar cosas que podrías ir probando para mejorar.&lt;/p&gt;

&lt;p&gt;Por último, te dejo algunas acciones que puedes intentar aplicar para ir reduciendo algunos de los problemas de Gitflow.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Elimina develop.&lt;/strong&gt; ¿Para qué necesitas dos ramas de larga duración? Ten sólo main e intenta que cada vez que se haga merge de una rama haya un despliegue.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Acelera el feedback al desarrollar  código.&lt;/strong&gt; Hacer pair programming o una reunión corta es más rápido para obtener feedback que esperar a terminar la tarea para hacer una pull request.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Intenta que las revisiones de código no bloqueen la entrega de valor.&lt;/strong&gt; Existen formas de hacer reviews de código no bloqueantes como los concerns. Echa un vistazo a la &lt;a href=&quot;https://www.youtube.com/watch?v=pp8j1ggCaoM&quot;&gt;charla de Xavi Gost sobre concerns&lt;/a&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3].&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Reduce el tamaño de tus pull requests.&lt;/strong&gt; No tienes porqué hacer una PR con toda la tarea terminada. Si has hecho un refactor previo a la tarea que mejora lo que había antes, haz un PR y mergealo ya. ¿Has avanzado una parte de la tarea que no modifica comportamiento observable para el usuario? ¡Mergéalo! Acabarás teniendo pull requests tan pequeños que dar el salto a commitear en main te parecerá natural.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Al respecto de tener dos formas de desplegar en producción, &lt;a href=&quot;https://twitter.com/mipsytipsy/status/1459731465994866691&quot;&gt;Charity Majors&lt;/a&gt; publica un tweet diciendo que solo debería haber una forma de desplegar, y no tener una forma corta “insegura” para usar justo en los momentos de estrés.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] En la charla &lt;a href=&quot;https://www.youtube.com/watch?v=vqEg37e4Mkw&quot;&gt;Workflows of refactoring&lt;/a&gt; Martin Fowler explica el concepto de refactoring oportunista.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] &lt;a href=&quot;https://humanwhocodes.com/blog/2015/04/14/consensus-driven-development/&quot;&gt;Otro post&lt;/a&gt; relacionado con el concepto de Consensus-Driven Development de Nicholas C. Zakas&lt;/p&gt;
</description>
          <pubDate>2022-01-25T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2022/01/integracion-continua</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2022/01/integracion-continua</guid>
        </item>
      
    
      
        <item>
          <title>Entrevistas para la Agile Alliance</title>
          <description>&lt;p&gt;Hace unos meses, nuestros compañeros de Codesai, &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Toño de la Torre&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel Viera&lt;/a&gt; participaron en una serie de entrevistas para la &lt;a href=&quot;https://twitter.com/AgileAlliance&quot;&gt;Agile Alliance&lt;/a&gt; de mano de &lt;a href=&quot;https://twitter.com/juanbandajara&quot;&gt;Juan Banda&lt;/a&gt;, quién en una iniciativa por llevar más representación de la opinión técnica al mundo Agile, contactó con ellos para hablar de algún tema que les pareciera interesante compartir. En este caso, sobre Caring y DDD.&lt;/p&gt;

&lt;p&gt;Queríamos compartir estas charlas con la comunidad y añadirlas en una entrada en nuestro blog. Esperamos las disfrutes y cualquier feedback sobre las mismas será bien recibido.&lt;/p&gt;

&lt;p&gt;Primero os dejamos la charla de Toño, que viene a traer un poco más de contexto al gran post que nuestro compañero &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt; ya publicó sobre “&lt;a href=&quot;https://codesai.com/2020/06/caring&quot;&gt;The Value of Caring&lt;/a&gt;” en nuestro blog hace varios meses. En ella Toño cuenta su experencia personal aplicando esta filosofía en equipos con los que ha trabajado. ¡Muchas gracias Toño!&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Sk3JfHF6BWU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Por otro lado, Miguel tuvo también su entrevista sobre DDD, hablando un poco sobre en qué se fundamenta esta metodología de desarrollo, hablando de prácticas y principios en los que se basa, comentando cómo la industria ha entendido DDD y que puede hacer, según su opinión para continuar llevando estos conocimientos al mundo del software. Además ofrece su visión de por qué DDD no ha triunfado tanto como otras tantas alternativas que existen en el mundo del software. ¡Muchas gracias Miguel!&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Efv2kkMA4RU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Y nada más, agradecer a Juan Banda por contar con nosotros para esta serie de entrevistas y a la Agile Alliance por permitir este tipo de iniciativas por seguir compartiendo conocimiento y apostando por visibilizar la importancia del trabajo técnico y no solo en el proceso a la hora de desarrollar software.&lt;/p&gt;
</description>
          <pubDate>2021-02-10T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2021/02/agile-alliance</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2021/02/agile-alliance</guid>
        </item>
      
    
      
        <item>
          <title>Recapitulando nuestra experiencia con Connectsai</title>
          <description>&lt;p&gt;Este post viene a solucionar una de las espinas clavadas que quedaban en nuestro backlog de publicaciones pendientes. Y esto es contaros nuestra experiencia con el Open Space remoto Connectsai.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/toño-connectsai.jpeg&quot; alt=&quot;Toño Connectsai&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hace unos meses (el sábado 17 de octubre) montamos conjuntamente con &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt; el que sería nuestro primer evento de autor: &lt;a href=&quot;https://codesai.com/connectsai&quot;&gt;Connectsai&lt;/a&gt;. La experiencia de montar el evento, como en todas las organizaciones, tiene sus claroscuros: incertidumbre sobre el nivel de asistencia, la retención de la gente a medida que pasa el día, el rendimiento de las herramientas para remote, cómo comunicar un evento de esta magnitud, si se puede sobrevivir sin patrocinadores y un largo etc.&lt;/p&gt;

&lt;p&gt;Pero con dudas o no, llegó el gran día y tuvimos la fortuna de que el evento contó con bastante asistencia, menos de la que hubiéramos querido, pero bastante más que nuestra predicción a la baja. La media de personas durante el evento era de 60 con un pico de asistencia de más de 90 personas. Pero sí que hay aprendizajes que creemos que podemos aportar en este pequeño post:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No sobrecargar de comunicación a la gente. Que sea efectiva y que sea fácil buscarla para cuando haya un momento en el que la gente se pierda.&lt;/li&gt;
  &lt;li&gt;Anima a la gente a que se conecte en espacios fuera de las charlas. El valor que más hemos percibido que no hemos podido proveer a la gente es la capacidad de que conecten entre si en espacios menos oficiales a la organización del evento.&lt;/li&gt;
  &lt;li&gt;Fomentar los valores de la organización, respeto, apertura, divergencia y sobretodo crear un espacio en el que la gente se sienta segura compartiendo.&lt;/li&gt;
  &lt;li&gt;Romper el hielo. En los open space remotos hemos notado que es más difícil empezar la retahíla de propuestas. Habla con gente que tenga temas que puedan dar en el open space para que empiecen las propuestas ellas, esto anima a que el resto se sume poco a poco.&lt;/li&gt;
  &lt;li&gt;Si vas a grabar la charla, que quede claro que es opcional. La gente puede echarse atrás por el miedo a que se grabe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/connectsai-wall.png&quot; alt=&quot;Connectsai Wall&quot; /&gt;
&lt;em&gt;Kudos a Aitor Alzola &lt;a href=&quot;https://twitter.com/aitortxu&quot;&gt;@aitortxu&lt;/a&gt; por su fantásticas manos para la facilitación gráfica&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Con todos estos aprendizajes, esperamos que en la siguiente edición (que no sabemos si se llamará así o no) podamos mejorar nuestro desempeño como organizadores. Aún así el feedback recibido ha sido muy positivo, la gente ha disfrutado mucho del evento, de volver a encontrarse con gente, y sobretodo del nivel de las charlas preparadas que teníamos con las speakers que se mostraron dispuestas a colaborar en ese día con nosotros. Desde aquí queremos dar las gracias por brindarnos su tiempo y esfuerzo para que esto saliera bien.&lt;/p&gt;

&lt;p&gt;Por último queríamos compartir la lista de las charlas grabadas que se encuentra en nuestro canal de Youtube en la lista de &lt;a href=&quot;https://www.youtube.com/watch?v=FpZWD-HsIvY&amp;amp;list=PL9TlRsoJAtQal5HwlbfqHgVszGCEmDIy_&quot;&gt;Connectsai&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;También aprovechamos para compartir la charla en este post la charla de Mitos y Leyendas de DDD que dieron nuestros compañeros Miguel Viera &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;@mangelviera&lt;/a&gt; y Alfredo Casado &lt;a href=&quot;https://twitter.com/AlfredoCasado&quot;&gt;@AlfredoCasado&lt;/a&gt;:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/PXbql2aWMs4&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos&lt;/h2&gt;

&lt;p&gt;No queríamos marcharnos sin agradecer a Lifull Connect por su tiempo y esfuerzo en lograr que esto haya sido posible, estamos deseando volver a colaborar para una nueva edición.&lt;/p&gt;

&lt;p&gt;Y por último a todas las speakers y facilitadoras que han pasado por esta edición y que queremos hacerles un hueco en este post:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/IngridAstiz&quot;&gt;Ingrid Astiz&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Toño de la Torre&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/finuka&quot;&gt;Josefina Pérez&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/nyan_dev&quot;&gt;Meritxell Calvo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/lainde&quot;&gt;Raquel Lainde&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/MartaMans0&quot;&gt;Marta Manso&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/zuko_mann&quot;&gt;Roman Zukov&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/cristina-del-canto&quot;&gt;Cristina del Canto&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/AdelaTort&quot;&gt;Adela Tort&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/nhan_bcn&quot;&gt;Ana Carmona&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/gecual&quot;&gt;Gema Cuenca&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/isma_tech&quot;&gt;Ismael Benítez&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Muchas gracias a todas y nos vemos en el siguiente Connectsai.&lt;/p&gt;
</description>
          <pubDate>2021-02-04T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2021/02/connectsai</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2021/02/connectsai</guid>
        </item>
      
    
      
        <item>
          <title>Notes on OCP from Agile Principles, Practices and Patterns book</title>
          <description>&lt;p&gt;Some time ago I wrote a post sharing my &lt;a href=&quot;/2017/08/notes-on-srp&quot;&gt;notes on SRP from Agile Principles, Practices and Patterns book&lt;/a&gt; because I was making an effort to get closer to the sources of some object-oriented concepts. I didn’t continue sharing my notes on SOLID because I thought they might not be interesting for our readers. However, seeing the success of the &lt;a href=&quot;https://thebigbranchtheorypodcast.github.io/post/single-responsablity/&quot;&gt;Single responsibility ¿Principle? episode&lt;/a&gt; of &lt;a href=&quot;https://thebigbranchtheorypodcast.github.io/&quot;&gt;The Big Branch Theory Podcast&lt;/a&gt; for which I used my &lt;a href=&quot;/2017/08/notes-on-srp&quot;&gt;notes on SRP&lt;/a&gt;, I’ve decided to share the rest of my notes on SOLID on Codesai’s blog.&lt;/p&gt;

&lt;p&gt;Ok, so these are the raw notes I took while reading the chapter devoted to &lt;b&gt;Open-closed Principle&lt;/b&gt; in &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_Cecil_Martin&quot;&gt;Robert C. Martin&lt;/a&gt;’s &lt;a href=&quot;https://www.goodreads.com/book/show/84983.Agile_Principles_Patterns_and_Practices_in_C_&quot;&gt;Agile Principles, Practices and Patterns in C#&lt;/a&gt; book (I added some personal annotations between brackets):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;OCP -&amp;gt; “Software entities (classes, modules, functions, etc) should be open for extension but closed for modification”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“When a single change to a program results in a cascade of changes to dependent modules, the design smells of fragility” &amp;lt;- [No local consequences. See &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Beck&lt;/a&gt;’s &lt;strong&gt;Local Consequences&lt;/strong&gt; principle from &lt;a href=&quot;https://www.goodreads.com/book/show/781559.Implementation_Patterns&quot;&gt;Implementation Patterns&lt;/a&gt;] “OCP advises us to refactor the system so that further changes of that kind will not cause more modifications. If OCP is applied well, further changes of that kind are achieved by adding new code, not by changing old code that already works”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“It’s possible to create abstractions that are fixed and yet represent an unbounded group of possible behaviors”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“[A module that uses such abstractions] can be closed for modification, since it depends on an abstraction that is fixed. Yet the behavior of the module can be extended by creating new derivatives of the abstraction”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Abstract classes are more closely associated to their clients than to the classes that implement them” &amp;lt;- [related with &lt;a href=&quot;https://martinfowler.com/eaaCatalog/separatedInterface.html&quot;&gt;Separated Interface from Fowler’s P of EAA&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;”[&lt;a href=&quot;https://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;Strategy&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Template_method_pattern&quot;&gt;Template Method&lt;/a&gt; patterns] are the most common ways to satisfy OCP. They represent a clear separation of generic functionality from the detailed implementation of that functionality”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Anticipation&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;“[When a] program conforms to OCP. It is changed by adding code rather than by changing existing code”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“In general no matter how “closed” a module is, there will always be some kind of change against which it is not closed”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“Since &lt;strong&gt;closure&lt;/strong&gt; &amp;lt;- [“closure” here means protection against a given axis of variation or change, see &lt;a href=&quot;https://en.wikipedia.org/wiki/Craig_Larman&quot;&gt;Craig Larman&lt;/a&gt;’s &lt;a href=&quot;https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variation: The Importance of Being Closed&lt;/a&gt;] can’t be complete, it &lt;strong&gt;must be strategic&lt;/strong&gt;. That is the designer must choose the kinds of changes against which to close the design, must guess at the kinds of changes that are most likely, and then construct abstractions to protect against those changes.”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“This is not easy. It amounts to making educated guesses about the likely kinds of changes that the application will suffer over time.” “Also conforming to OCP is expensive. It takes development time and money to create the appropriate abstractions. These abstractions also increase the complexity of the software design”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“We want to limit the application of OCP to changes that are likely”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“How do we know which changes are likely? We do the appropriate research, we ask the appropriate questions, and we use our experience and common sense.” &amp;lt;- [also requires knowing about the domain. A bit easier to predict in technological boundaries. Listen to the conversation in &lt;a href=&quot;https://thebigbranchtheorypodcast.github.io/post/single-responsablity/&quot;&gt;Single Responsibility ¿Principle?&lt;/a&gt;] podcast] “And after all that, we wait until the changes happen!” &amp;lt;- [see &lt;a href=&quot;http://wiki.c2.com/?YouArentGonnaNeedIt&quot;&gt;Yagni&lt;/a&gt;] “We don’t want to load the design with lots of unnecessary abstractions. Rather we want to wait until we need the abstraction and then put them in”&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Fool me once”&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;“… we initially write our code expecting it not to change. When a change occurs, we implement the abstractions that protect us from future changes of that kind.” &amp;lt;- [One heuristic: we get to OCP through refactoring to avoid &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=13&quot;&gt;Speculative Generality&lt;/a&gt;. Most useful heuristic in unknown territory.]&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“If we decide to take the first bullet, it is to our advantage to get the bullets flying early and frequently. We want to know what changes are likely before we are very far down the development path. The longer we wait to find out what kind of changes are likely, the more difficult it will be to create the appropriate abstractions.”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“Therefore, we need to stimulate changes”&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;
            &lt;p&gt;“We write tests first” -&amp;gt; “testing is one kind of usage of the system. By writing tests first, we force the system to be testable. Therefore, changes in testability will not surprise us later. We will have built the abstractions that make the system testable. We are likely to find that many of these abstractions will protect us from other kinds of changes later.” &amp;lt;- [incrementally (tests “right after”) might also work]&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;“We use short development cycles”&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;“We develop features before infrastructure and frequently show those feature to stake-holders”&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;“We develop the most important features first”&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;“We release the software early and often”&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Closure is based on abstraction”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Using a data-driven approach to achieve closure” &amp;lt;- [OCP is not only an OO principle, see &lt;a href=&quot;https://en.wikipedia.org/wiki/Craig_Larman&quot;&gt;Craig Larman&lt;/a&gt;’s &lt;a href=&quot;https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variation: The Importance of Being Closed&lt;/a&gt; for more]&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;“If we must close the derivatives […] from knowledge of one another, we can use a table-driven approach”&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“The only item that is not closed against [the rule that involves] the various derivatives is the table itself. An that table can be placed in its own module, separated from all the other modules, so that changes to it do not affect any of the other modules”&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“In many ways the OCP is at the heart of OOD.”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Yet conformance to [OCP] is not achieved by using an OOP language. Nor is it a good idea to apply rampant abstraction to every part of the application. Rather it requires a dedication on the part of the developers to apply abstraction only to those parts of the program that exhibit frequent change. &amp;lt;- [applying &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Beck&lt;/a&gt;’s &lt;strong&gt;Rate of Change&lt;/strong&gt; principle from &lt;a href=&quot;https://www.goodreads.com/book/show/781559.Implementation_Patterns&quot;&gt;Implementation Patterns&lt;/a&gt;]”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“Resisting premature abstraction is as important as abstraction itself &amp;lt;-  [related to &lt;a href=&quot;https://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt;’s  &lt;a href=&quot;https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction&quot;&gt;“duplication is far cheaper than the wrong abstraction”&lt;/a&gt;]”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me getting closer to the sources of SOLID principles was a great experience that helped me to remove illusions of knowledge I had developed due to the telephone game effect caused by initially learning about SOLID through blog posts and talks. I hope these notes on OCP might be useful to you as well, and motivate you to read a bit closer to some of the sources.&lt;/p&gt;
</description>
          <pubDate>2021-01-29T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2021/01/notes-on-ocp</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2021/01/notes-on-ocp</guid>
        </item>
      
    
      
        <item>
          <title>Solving the Beverages Prices Refactoring kata (2): limiting the options on the menu</title>
          <description>&lt;h2&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;This is the second and last post in a series of posts showing a possible solution to &lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;the Beverages Prices Refactoring kata&lt;/a&gt; that I recently developed with some people from &lt;a href=&quot;https://www.meetup.com/wtmbcn/&quot;&gt;Women Tech Makers Barcelona&lt;/a&gt; with whom I’m working through &lt;a href=&quot;https://github.com/Codesai/practice_program&quot;&gt;Codesai’s Practice Program&lt;/a&gt; twice a month.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;/2020/11/solving-beverages-kata-1&quot;&gt;previous post&lt;/a&gt; we introduced a design based on composition that fixed the &lt;em&gt;Combinatorial Explosion&lt;/em&gt; code smell and produced a flexible solution applying the decorator design pattern. There was a potential problem in that solution because the client code, the code that needed to find out the price of the beverages, knew&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; too much about how to create and compose beverages and supplements.&lt;/p&gt;

&lt;p&gt;Have a look, for instance, at the following line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new WithCream(new WithMilk(new Coffee()))&lt;/code&gt;. It knows about three classes and how they are being composed. In the case of this kata, that might not be a big problem, since the client code is only comprised of a few tests, but, in a larger code base, this problem might spread across numerous classes generating a code smell known as &lt;em&gt;Creation Sprawl&lt;/em&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;
In this post, we’ll try to reduce client knowledge of concrete component and decorator classes and their composition by encapsulating all the creational knowledge behind a nice, readable interface that we’ll keep all the complexity of combining the supplements (decorators) and beverages (components) hidden from the client code.&lt;/p&gt;

&lt;p&gt;Another more subtle problem with this design based on composition has to do with something that we have lost: the fact that not all combinations of beverages and supplements were allowed on the menu. That knowledge was implicitly encoded in the initial inheritance hierarchy, and disappeared with it. In the current design we can dynamically create any combination of beverages and supplements, including those that were not included in the original menu, like, for instance a tea with cinnamon, milk and cream (doing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new WithCinnamon(new WithCream(new WithMilk(new Tea())))&lt;/code&gt;) which you might find delicious :).We’ll also explore possible ways to recover that limitation of options.&lt;/p&gt;

&lt;p&gt;We’ll start by examining some creational patterns that are usually applied along with the decorator design pattern.&lt;/p&gt;

&lt;h2 id=&quot;would-the-factory-pattern-help&quot;&gt;Would the &lt;em&gt;Factory pattern&lt;/em&gt; help?&lt;/h2&gt;

&lt;p&gt;In order to encapsulate the creational code and hide its details from client code, we might use the &lt;em&gt;factory pattern&lt;/em&gt; described by &lt;a href=&quot;https://wiki.c2.com/?JoshuaKerievsky&quot;&gt;Joshua Kerievsky&lt;/a&gt; in his &lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt;. A &lt;em&gt;factory&lt;/em&gt; is a class that implements one or more &lt;em&gt;Creation Methods&lt;/em&gt;. A &lt;em&gt;Creation Method&lt;/em&gt; is a static or non-static method the creates and returns an object instance&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We might apply the &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1398606&amp;amp;seqNum=3&quot;&gt;Encapsulate Classes with Factory&lt;/a&gt; refactoring&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; to introduce a &lt;em&gt;factory&lt;/em&gt; class with an interface which provided a &lt;em&gt;creation method&lt;/em&gt; for each entry on the menu, that is, it would have a method for making  coffee, another one for making tea, another one for making coffee with milk, and so on, and so forth.&lt;/p&gt;

&lt;p&gt;Before starting to refactor, let’s think a bit about the consequences of introducing this pattern to assess if it will leave us in a better design spot or not. At first sight, introducing the &lt;em&gt;factory pattern&lt;/em&gt; seems to simplify client code and reduce the overall coupling because it encapsulates all the creational logic hiding the complexity related to composing decorators and components behind its interface which solves the first problem we discussed in the introduction. The second one, limiting the combinations of beverages and supplements to only the ones available on the menu, is solved just by limiting the methods in the interface of the &lt;em&gt;factory&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, it would also create a maintenance problem somehow similar to the initial &lt;em&gt;combinatorial explosion&lt;/em&gt; code smell we were trying to avoid when we decided to introduce the decorator design pattern. As we said, the interface of the &lt;em&gt;factory&lt;/em&gt; would have a method for each combination of beverages and supplements available on the menu. This means that to add a new supplement we’d have to multiply the number of &lt;em&gt;Creation methods&lt;/em&gt; in the interface of the &lt;em&gt;factory&lt;/em&gt; by two. So, we might say that, introducing the  &lt;em&gt;factory pattern&lt;/em&gt;,  we’d get an interface suffering from a &lt;em&gt;combinatorial explosion of methods&lt;/em&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Knowing that, we might conclude that a solution using the &lt;em&gt;factory pattern&lt;/em&gt; would be interesting only when having a small number of options or if we didn’t expect the number of supplements to grow. As we said in the previous post, we think it likely that we’ll be required to add new supplements so we prefer a design that is easy to evolve along the axis of change of adding new supplements&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. This means the &lt;em&gt;factory pattern&lt;/em&gt; is not the way to go for us this time because it’s not flexible enough for our current needs. We’ll have to explore more flexible alternatives&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;lets-try-using-the-builder-design-pattern&quot;&gt;Let’s try using the &lt;em&gt;Builder design pattern&lt;/em&gt;.&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;builder design pattern&lt;/em&gt; is often used for constructing complex and/or composite objects&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;. Using it we might create a nice readable interface to compose the beverages and supplements bit by bit. Like the &lt;em&gt;factory pattern&lt;/em&gt;, a &lt;em&gt;builder&lt;/em&gt; would encapsulate the complexity of combining decorators from the client code. Unlike the &lt;em&gt;factory pattern&lt;/em&gt;, a &lt;em&gt;builder&lt;/em&gt; allows to construct the composite following a varying process. It’s this last characteristic that will avoid the  &lt;em&gt;combinatorial explosion of methods&lt;/em&gt; that made us discard the &lt;em&gt;factory pattern&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this case you can introduce the builder by applying the &lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1398606&amp;amp;seqNum=5&quot;&gt;Encapsulate Composite with Builder&lt;/a&gt;. Let’s have a look at how we implemented it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9603a635892e6f29b574bfcfe7a983d5.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how we keep the state of the partially composed object and apply the decorations incrementally until it’s returned by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; method. Notice also how the beverage is the initial state in the process of creating the composite object.&lt;/p&gt;

&lt;p&gt;These are the tests after introducing the &lt;em&gt;builder design pattern&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/53f2f13a7d13348d58782f57afe3bd90.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interface&lt;/a&gt; that we decided for the builder. Although a fluent interface is not a requirement to write a builder, we think it reads nice.&lt;/p&gt;

&lt;p&gt;As we said before, using a builder does not suffer from the combinatorial explosion of methods that the &lt;em&gt;factory pattern&lt;/em&gt; did. The builder design pattern is more flexible than the &lt;em&gt;factory pattern&lt;/em&gt; which makes it more suitable for composing components and decorators.&lt;/p&gt;

&lt;p&gt;Still, our success is only partial because the builder can create any combination of beverages and supplements. A drawback of using a &lt;em&gt;builder&lt;/em&gt; instead of a &lt;em&gt;factory&lt;/em&gt; is usually that clients require to have more domain knowledge. In this case, the current solution forces the client code to hold a bit of domain knowledge: it knows which combinations of beverages and supplements are available on the menu.&lt;/p&gt;

&lt;p&gt;We’ll fix this last problem in the next section.&lt;/p&gt;

&lt;h2 id=&quot;a-hybrid-solution-combining-factory-and-builder-patterns&quot;&gt;A hybrid solution combining &lt;em&gt;factory&lt;/em&gt; and &lt;em&gt;builder&lt;/em&gt; patterns.&lt;/h2&gt;
&lt;p&gt;Let’s try to limit the possible combinations of beverages and supplements to the options on the menu by combining the &lt;em&gt;creation methods&lt;/em&gt; of the &lt;em&gt;factory pattern&lt;/em&gt; and the &lt;em&gt;builder design pattern&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To do so, we added to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt; the &lt;em&gt;creation methods&lt;/em&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coffee&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tea&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotChocolate&lt;/code&gt;, that create different &lt;em&gt;builders&lt;/em&gt; for each type of beverage: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoffeeBuilder&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TeaBuilder&lt;/code&gt;and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HotChocolateBuilder&lt;/code&gt;, respectively. Each of the &lt;em&gt;builders&lt;/em&gt; has only the public methods to select the supplements which are possible on the menu for a given type of beverage.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/052e9e066edab3a14f7527bbe290a332.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice that we chose to write the &lt;em&gt;builders&lt;/em&gt; as &lt;em&gt;inner classes&lt;/em&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt; class. They could have been independent classes, but we prefer &lt;strong&gt;inner classes&lt;/strong&gt; because the &lt;em&gt;builders&lt;/em&gt; are only used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt; and this way they don’t appear anywhere else.&lt;/p&gt;

&lt;p&gt;This is the first design that solves the problem of limiting the possible combinations of beverages and supplements to only the options on the menu. It still encapsulates the creational logic and still reads well. In fact the tests haven’t changed at all because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt;’s public interface is exactly the same.&lt;/p&gt;

&lt;p&gt;However, the new &lt;em&gt;builders&lt;/em&gt; present duplication: the code related to supplements that can be used with different beverages and the code in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;What is different for the clients that call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coffee&lt;/code&gt; method and the clients that call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tea&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotChocolate&lt;/code&gt; methods are the public methods they can use on each builder, that is, their interfaces. When we had only one &lt;em&gt;builder&lt;/em&gt;, we had an interface with methods that were not interesting for some of its clients.&lt;/p&gt;

&lt;p&gt;By having three &lt;em&gt;builders&lt;/em&gt; we segregated the interfaces so that no client was forced to depend on methods it does not use&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;. However we didn’t need to introduce classes to segregate the interfaces, we could have just used, well, interfaces. As we’ll see in the next section using interfaces would have avoided the duplication in the implementation of the &lt;em&gt;builders&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Segregating interfaces better by using interfaces. &lt;/h2&gt;

&lt;p&gt;As we said, instead of directly using three different &lt;em&gt;builder&lt;/em&gt; classes, it’s better to use three interfaces, one for each kind of &lt;em&gt;builder&lt;/em&gt;. That would also comply with the &lt;a href=&quot;https://wiki.c2.com/?InterfaceSegregationPrinciple&quot;&gt;Interface Segregation Principle&lt;/a&gt;, but, using the interfaces helps us avoid having duplicated code in the implementation of the &lt;em&gt;builders&lt;/em&gt;, because we can write only one builder class, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Beverage Machine&lt;/code&gt;, that implements the three interfaces.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/668a601f7f092d93050ec3ec10d115ec.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how, in the creation methods, we feed the base beverage into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt; through its constructor, and how each of those creation methods return the appropriate interface. Notice also that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeverageMachine&lt;/code&gt;’s public interface remains the same, so this refactor won’t change the tests at all. You can check the resulting builder interfaces in Gist: &lt;a href=&quot;https://gist.github.com/trikitrok/9420325932714352a09c685786e18f1c&quot;&gt;TeaBuilder&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/trikitrok/0c4af1a07ad0fa3b65fddf4b1d71b1be&quot;&gt;HotChocolateBuilder&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/trikitrok/222265947f93435c7fef4ea07075e185&quot;&gt;CoffeeBuilder&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Conclusions. &lt;/h2&gt;
&lt;p&gt;In this last post of the series dedicated to the &lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;Beverages Prices Refactoring kata&lt;/a&gt;, we’ve explored different ways to avoid &lt;em&gt;creation sprawl&lt;/em&gt;, reduce coupling with client code and reduce implicit creational domain knowledge in client code. In doing so, we have learned about and applied several creational patterns (&lt;em&gt;factory pattern&lt;/em&gt;, and &lt;em&gt;builder design pattern&lt;/em&gt;), and some related refactorings. We have also used some design principles (such as &lt;em&gt;coupling&lt;/em&gt;, &lt;em&gt;open-closed principle&lt;/em&gt; or &lt;em&gt;interface segregation principle&lt;/em&gt;), and code smells (such as &lt;em&gt;combinatorial explosion&lt;/em&gt; or &lt;em&gt;creation sprawl&lt;/em&gt;) to judge different solutions and guide our refactorings.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank the WTM study group, and especially &lt;a href=&quot;https://twitter.com/InmaCNavas&quot;&gt;Inma Navas&lt;/a&gt; for solving this kata with me. Thanks also to my Codesai colleagues and to &lt;a href=&quot;https://twitter.com/InmaCNavas&quot;&gt;Inma Navas&lt;/a&gt; for reading the initial drafts and giving me feedback and to &lt;a href=&quot;https://www.pexels.com/@amelia-hallsworth&quot;&gt;Amelia Hallsworth&lt;/a&gt; for the picture.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Knowledge here means coupling or &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;connascence&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] &lt;em&gt;Creation Sprawl&lt;/em&gt; is a code smell that happens when the knowledge for creating an object is spread out across numerous classes, so that creational responsibilities are placed in classes that should now be playing any role in object creation. This code smell was described by &lt;a href=&quot;https://wiki.c2.com/?JoshuaKerievsky&quot;&gt;Joshua Kerievsky&lt;/a&gt; in his &lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt; book.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Don’t confuse the &lt;em&gt;Factory Pattern&lt;/em&gt; with design patterns with similar names like &lt;a href=&quot;https://en.wikipedia.org/wiki/Factory_method_pattern&quot;&gt;Factory method pattern&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_factory_pattern&quot;&gt;Abstract factory pattern&lt;/a&gt;. These two design patterns are creational patterns described in the &lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt; book.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;Factory Method&lt;/em&gt; is “a non-static method that returns a base class or an interface type and that is implemented in a hierarchy to enable polymorphic creation” whereas an &lt;em&gt;Abstract Factory&lt;/em&gt; is “an interface for creating fqamiñlies of related or dependent objects without specifying their concrete classes”.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Factory Pattern&lt;/em&gt; a &lt;em&gt;Factory&lt;/em&gt; is “any class that implements one or more &lt;em&gt;Creation Methods&lt;/em&gt;” which are “static or non-static methods that create and return an object instance”. This definition is more general. Every &lt;em&gt;Abstract Factory&lt;/em&gt; is a &lt;em&gt;Factory&lt;/em&gt; (but not the other way around), and every &lt;em&gt;Factory Method&lt;/em&gt; is a &lt;em&gt;Creation Method&lt;/em&gt; (but not necessarily the reverse). &lt;em&gt;Creation Method&lt;/em&gt; also includes what &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt; called “factory method” in &lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring&lt;/a&gt; (which is not the &lt;em&gt;Factory Method&lt;/em&gt; design pattern) and &lt;a href=&quot;https://en.wikipedia.org/wiki/Joshua_Bloch&quot;&gt;Joshua Bloch&lt;/a&gt; called “static factory” (probably a less confusing name than Fowler’s one) in &lt;a href=&quot;https://www.goodreads.com/book/show/34927404-effective-java&quot;&gt;Effective Java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Presented in the fourth chapter of &lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt; that is dedicated to Creational Patterns.
&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] If you remember the previous post, before introducing the decorator design pattern, we suffered from a &lt;em&gt;combinatorial explosion of classes&lt;/em&gt; (adding a new supplement meant multiplying the number of classes by two). Now, the factory interface (its public methods) would suffer a &lt;em&gt;combinatorial explosion of methods&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] In other words: that it’s [protected against that type of variation (https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] This is common when working with creational patterns. All of them encapsulate knowledge about which concrete classes are used and hide how instances of these classes are created and put together, but some are more flexible than others. It’s usual to start using a &lt;em&gt;Factory pattern&lt;/em&gt; and evolve toward the other creational patterns as we realize more flexibility is needed.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] We have devoted several posts to builders: &lt;a href=&quot;/2015/07/remove-data-structures-noise-from-your-tests-with-builders&quot;&gt;Remove data structures noise from your tests with builders&lt;/a&gt;, &lt;a href=&quot;/2016/10/refactoring-tests-using-builder-functions-in-clojure-clojureScript&quot;&gt;Refactoring tests using builder functions in Clojure/ClojureScript&lt;/a&gt;, &lt;a href=&quot;/2017/08/cop-builders-and-fluid-interfaces&quot;&gt;In a small piece of code&lt;/a&gt;, &lt;a href=&quot;/2019/05/negative-builder&quot;&gt;The curious case of the negative builder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] Following the &lt;a href=&quot;https://en.wikipedia.org/wiki/Interface_segregation_principle&quot;&gt;Interface Segregation Principle&lt;/a&gt; that states that “no client should be forced to depend on methods it does not use”.&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;h3 id=&quot;books&quot;&gt;Books&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85041.Refactoring_to_Patterns&quot;&gt;Refactoring to Patterns&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?JoshuaKerievsky&quot;&gt;Joshua Kerievsky&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Erich_Gamma&quot;&gt;Erich Gamma&lt;/a&gt;, &lt;a href=&quot;http://software-pattern.org/Author/29&quot;&gt;Ralph Johnson&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Vlissides&quot;&gt;John Vlissides&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?RichardHelm&quot;&gt;Richard Helm&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/58128.Head_First_Design_Patterns&quot;&gt;Head First Design Patterns&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Eric_Freeman_(writer)&quot;&gt;Eric Freeman&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Kathy_Sierra&quot;&gt;Kathy Sierra&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/bertbates?lang=en&quot;&gt;Bert Bates&lt;/a&gt;, &lt;a href=&quot;https://www.elisabethrobson.com/&quot;&gt;Elisabeth Robson&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;articles&quot;&gt;Articles&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1398606&amp;amp;seqNum=3&quot;&gt;Encapsulate Classes with Factory&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?JoshuaKerievsky&quot;&gt;Joshua Kerievsky&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.informit.com/articles/article.aspx?p=1398606&amp;amp;seqNum=5&quot;&gt;Encapsulate Composite with Builder&lt;/a&gt;, &lt;a href=&quot;https://wiki.c2.com/?JoshuaKerievsky&quot;&gt;Joshua Kerievsky&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/2017/01/about-connascence&quot;&gt;About Connascence&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Factory_method_pattern&quot;&gt;Factory method design pattern&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Builder_pattern&quot;&gt;Builder design pattern&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_factory_pattern&quot;&gt;Abstract factory pattern&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;The Beverages Prices Refactoring kata: a kata to practice refactoring away from an awful application of inheritance&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/2020/11/solving-beverages-kata-1&quot;&gt;Solving the Beverages Prices Refactoring kata (1): composition over inheritance&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variation: The Importance of BeingClosed&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Craig_Larman&quot;&gt;Craig Larman&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Interface_segregation_principle&quot;&gt;Interface Segregation Principle&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
          <pubDate>2021-01-20T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2021/01/solving-beverages-kata-2</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2021/01/solving-beverages-kata-2</guid>
        </item>
      
    
      
        <item>
          <title>Testeando una integración con SNS</title>
          <description>&lt;p&gt;En un &lt;a href=&quot;https://codesai.com/2020/10/testing-s3&quot;&gt;post anterior&lt;/a&gt; hablamos sobre cómo desarrollamos y testeamos una integración con S3 en uno de nuestros clientes. En esta segunda parte queríamos contar cómo ha sido nuestra experiencia con otro servicio de AWS: SNS.&lt;/p&gt;

&lt;h2 id=&quot;para-qué-usamos-sns&quot;&gt;¿Para qué usamos SNS?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/sns/&quot;&gt;Amazon SNS&lt;/a&gt; (Simple Notification Service) es un servicio de mensajería de Amazon que nos permite múltiples opciones de integración. Podemos configurar un topic de SNS para que cada vez que reciba un mensaje ejecute una lambda, envie un mail, reenvie ese mensaje a una o varias colas de SQS, etc.&lt;/p&gt;

&lt;figure style=&quot;margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/sns-communication.png&quot; alt=&quot;Flujo de comunicación con SNS&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Flujo de comunicación con SNS.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;En nuestro caso concreto, queríamos publicar una serie de eventos en un topic de SNS, y que luego éste enviase esos mensajes a una cola de SQS que consumía otro equipo.&lt;/p&gt;

&lt;h2 id=&quot;testeando-contra-sns&quot;&gt;Testeando contra SNS&lt;/h2&gt;

&lt;p&gt;Para conseguir que los tests contra SNS fueran lo más sencillos posible, redujimos al mínimo la lógica del  componente que se comunica con SNS&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. En nuestro caso, nos bastó con tener una interfaz con un único método encargada de enviar un mensaje en forma de diccionario.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/ef909b3917074823cc17e703679ebc33.js?file=Notifier.php&quot;&gt;&lt;/script&gt;

&lt;p&gt;De esta forma, la lógica de cuándo se tienen que enviar los mensajes y el formato de éstos quedaba segregada en otros componentes que podíamos testear de manera unitaria sin depender de servicios externos.&lt;/p&gt;

&lt;p&gt;Para comprobar el envío del mensaje en sí, pensamos en escribir un test de integración que publicase un mensaje con nuestro servicio &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SnsNotifier&lt;/code&gt; y comprobase que recibimos ese mensaje en el test. Siguiendo &lt;a href=&quot;https://codesai.com/2020/10/testing-s3&quot;&gt;el mismo enfoque que con S3&lt;/a&gt;, buscamos una imagen de Docker que nos permitiera escribir estos tests de integración.
En este caso elegimos usar la imagen &lt;a href=&quot;https://hub.docker.com/r/s12v/sns/&quot;&gt;s12v/sns&lt;/a&gt;, que nos proporciona una versión falsa de SNS contra la que podemos trabajar. No es una versión oficial mantenida por Amazon, pero nos sirvió para lo que queríamos.&lt;/p&gt;

&lt;p&gt;Aún disponiendo de esta imagen nos dimos cuenta de que este test de integración no iba a ser tan sencillo como el de S3. Como ya dijimos, SNS es un servicio de mensajería, y su API sólo deja enviar mensajes y suscribir otros componentes a un topic. No tenemos una forma de pedir directamente los mensajes relacionados con un topic. Esto complicaba un poco el testing porque requería  montar una pieza extra que fuese capaz de recibir los mensajes que íbamos a publicar.&lt;/p&gt;

&lt;p&gt;La documentación de s12v/sns proporciona un listado de integraciones soportadas con las que se podrían hacer esas comprobaciones. La opción de integrar a través de ficheros nos pareció sencilla. Supusimos que sería simplemente especificar la ruta a un fichero y luego leer el contenido del fichero para recuperar el mensaje. Sin embargo, no había documentación sobre cómo hacerlo funcionar y no lo conseguimos. Optamos por hacer el test integrando a través de SQS, que, además, era justo lo que se usaría en producción.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/sqs/&quot;&gt;Amazon SQS&lt;/a&gt; (Simple Queue Service) es el servicio de colas de AWS. Para los tests usamos la imagen &lt;a href=&quot;https://github.com/roribio/alpine-sqs&quot;&gt;roribio16/alpine-sqs&lt;/a&gt;, que nos da una versión falsa de SQS sobre la que podemos enviar y recibir mensajes. Tampoco es una versión oficial mantenida por AWS, pero de momento nos ha funcionado y nos da también una interfaz gráfica para consultar los mensajes pendientes de procesar.&lt;/p&gt;

&lt;p&gt;El procedimiento del test de integración sería el siguiente:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Crear un topic de SNS&lt;/li&gt;
  &lt;li&gt;Crear una cola de SQS.&lt;/li&gt;
  &lt;li&gt;Suscribimos la cola al topic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Publicamos un mensaje a través de nuestra clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SnsNotifier&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Verificamos que el mensaje ha llegado a la cola de SQS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Siguiendo esta idea así quedó el código del test que comprobaba el envío de un evento a SNS.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/ef909b3917074823cc17e703679ebc33.js?file=SnsNotifierTest.php&quot;&gt;&lt;/script&gt;

&lt;p&gt;Dado que la publicación de mensajes en SNS es asíncrona, en este test usamos un helper para hacer una aserción usando la técnica de polling and probing, &lt;a href=&quot;https://codesai.com/2020/10/polling-and-probing&quot;&gt;como explicaba Manuel Rivero en este post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;tests-en-producción&quot;&gt;¿Tests en producción?&lt;/h2&gt;

&lt;p&gt;En el post sobre la integración con S3 hablamos de la importancia de testear en producción para asegurarnos que todo funciona como es debido. En este caso tenemos alguna idea sobre lo que nos gustaría hacer, pero no hemos llegado a implementar nada aún porque, de momento, no hemos querido invertir más en esta feature.&lt;/p&gt;

&lt;p&gt;Lo que nos interesaría probar en producción es que si la aplicación lanza un evento, éste llega a los suscriptores del topic de SNS. Para conseguirlo podríamos seguir un enfoque parecido al que utilizamos para testear la integración con S3: tener un proceso que publique periódicamente un evento y revisar que se puede consumir en el otro extremo. Hemos pensado que desplegar un cronjob que periódicamente llame a un endpoint de la API que publique un evento en SNS, y suscribir una cola nueva a este topic y leer de la cola podría servir para verificar que el mensaje llega.&lt;/p&gt;

&lt;p&gt;Lo ideal sería que ese evento se publique en el mismo topic que se usa para los eventos reales, pero tendríamos que evitar que ese evento provoque efectos no deseados en el entorno de producción. En este punto se nos ocurren 2 maneras alternativas para conseguirlo:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Usar un evento de la aplicación que sea idempotente y sobre un dato que controlemos. Por ejemplo, teniendo un anuncio en producción que está despublicado, podemos llamar a un endpoint que haga que un anuncio deje de estar publicado, que lanzará el evento correspondiente. Validando el evento que llega, podríamos testear el servicio sin producir ningún efecto visible en producción. Sin embargo, puede que en el futuro no quisiéramos que se propaguen eventos cuando no hay cambio de estado o que haya algún cambio en cómo se gestiona el evento y rompamos nuestro test por el motivo que no esperamos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Por otro lado, podemos acordar con el equipo que está consumiendo eventos un evento sintético que ellos puedan ignorar, pero que nosotros podamos verificar por nuestro lado. Necesitaríamos un poco más de coordinación entre equipos y algo más de código custom para las pruebas, pero nos aseguraríamos que el test en producción solo se rompería por los motivos adecuados.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Como ya hemos dicho, aún no hemos testeado esta integración  en producción ni tomado una decisión firme sobre cómo hacerlo. Eso será material para otra publicación en la que detallaremos lo que hayamos hecho.&lt;/p&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos&lt;/h2&gt;

&lt;p&gt;Gracias a mis compañeros de Codesai por el feedback en las versiones iniciales de este post y al equipo de B2B de LifullConnect por ser parte del trabajo que se describe aquí.&lt;/p&gt;

&lt;h2 id=&quot;notas&quot;&gt;Notas&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Esta técnica se denomina &lt;a href=&quot;http://xunitpatterns.com/Humble%20Object.html&quot;&gt;Humble Object&lt;/a&gt; del libro xUnit Test Patterns de Gerard Meszaros&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/337302.xUnit_Test_Patterns&quot;&gt;xUnit Test Patterns, Refactoring Test Code, Gerard Meszaros&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codesai.com/2020/10/testing-s3&quot;&gt;Testeando una integración con S3&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/@copyconstruct/testing-in-production-the-safe-way-18ca102d0ef1&quot;&gt;Testing in production the safe way&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/copyconstruct&quot;&gt;Cindy Sridharan&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2020-12-07T11:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/12/testing-sns</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/12/testing-sns</guid>
        </item>
      
    
      
        <item>
          <title>Solving the Beverages Prices Refactoring kata (1): composition over inheritance</title>
          <description>&lt;h2&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;We are going to show a possible solution to &lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;the Beverages Prices Refactoring kata&lt;/a&gt; that we developed recently with some people from &lt;a href=&quot;https://www.meetup.com/wtmbcn/&quot;&gt;Women Tech Makers Barcelona&lt;/a&gt; with whom I’m doing &lt;a href=&quot;https://github.com/Codesai/practice_program&quot;&gt;Codesai’s Practice Program&lt;/a&gt; twice a month.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;The Beverages Prices Refactoring kata&lt;/a&gt; shows an example of inheritance gone astray. The initial code computes the price of the different beverages that are sold in a coffee house. There are some supplements that can be added to those beverages. Each supplement increases the price a bit. Not all combinations of drinks and supplements are possible.&lt;/p&gt;

&lt;p&gt;As part of the kata, we are asked to &lt;strong&gt;add an optional cinnamon supplement that costs 0.05€ to all our existing catalog of beverages&lt;/strong&gt;. We are also advised to refactor the initial code a bit before introducing the new feature. Let’s see why.&lt;/p&gt;

&lt;h2&gt;The initial code. &lt;/h2&gt;

&lt;p&gt;To get an idea of the kind of problem we are facing, we’ll have a look at the code. There are 8 files: a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Beverage&lt;/code&gt; interface and 7 classes, one for each type of beverage and one for each allowed combination of beverages and supplements.&lt;/p&gt;

&lt;figure style=&quot;overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverage_kata_initial_code_folder.png&quot; alt=&quot;initial code files&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Initial code.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;A closer look reveals that the initial design uses inheritance and polymorphism to enable the differences in computing the price of each allowed combination of beverage and supplements. This is the inheritance hierarchy:&lt;/p&gt;

&lt;figure style=&quot;overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverage_kata_initial_uml.jpg&quot; alt=&quot;Inheritance hierarchy in the initial code&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Class diagram showing the inheritance hierarchy in the initial code.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If that diagram is not enough to scare you, have a quick look at the unit tests of the code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a9b2b77762045a77cfd9c6854046add7.js&quot;&gt;&lt;/script&gt;

&lt;h2&gt;First, we make the change easy&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. &lt;/h2&gt;

&lt;p&gt;Given the current design, if we decided to add the new feature straight away, we would end up with 14 classes (2 times the initial number of classes). If you think about it, this would happen for each new supplement we were required to add: we would be forced to double the number of classes. Adding n supplements more would mean multiplying the initial number of classes by 2&lt;sup&gt;n&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;This exponential growth in the number of classes is a typical symptom of a code smell called &lt;strong&gt;Combinatorial Explosion&lt;/strong&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. In this particular case the problem is caused by using inheritance to represent the pricing of beverages plus supplements.&lt;/p&gt;

&lt;p&gt;In order to introduce the new cinnamon supplement, we thought sensible to do a bit of preparatory refactoring first in order to remove the &lt;strong&gt;Combinatorial Explosion&lt;/strong&gt; code smell. The recommended refactoring for this code smell is &lt;a href=&quot;https://refactoring.com/catalog/replaceSuperclassWithDelegate.html&quot;&gt;Replace Inheritance with Delegation&lt;/a&gt; which leads to a code that uses composition instead of inheritance to avoid the combinatorial explosion. If all the variants&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; (supplements) keep the same interface, we’d be creating an example of the decorator design pattern&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;figure style=&quot;max-height:500px; max-width:500px; overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverage_kata_decorator_uml.jpg&quot; alt=&quot;Class diagram for the decorator design pattern&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Class diagram for the decorator design pattern&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The decorator pattern provides an alternative to subclassing for extending behavior. It involves a set of decorator classes that wrap concrete components and keep the same interface that the concrete components. A decorator changes the behavior of a wrapped component by adding new functionality before and/or after delegating to the concrete component.&lt;/p&gt;

&lt;p&gt;Applying the decorator pattern design to compute the pricing of beverages plus supplements, the beverages would correspond to the concrete components, tea, coffee and hot chocolate; whereas the supplements, milk and cream would correspond to the decorators.&lt;/p&gt;

&lt;figure style=&quot;max-height:700px; max-width:700px; overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverage_kata_refactoring_uml.jpg&quot; alt=&quot;New design class diagram using the decorator design pattern&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Design using the decorator design pattern to compute the pricing of beverages plus supplements.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We can obtain the behavior for a given combination of supplements and beverage by composing supplements (decorators) with a beverage (base component).&lt;/p&gt;

&lt;p&gt;For instance, if we had the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WithMilk&lt;/code&gt; decorator for the milk supplement pricing,&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7933c57fa80cca49b4e50b8f7b218a87.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;we would compose it with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tea&lt;/code&gt; instance to create the behavior that computes the price of a tea with milk:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8b351378049afcdd127a9c78b8f60913.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;A nice thing about decorators is that, since they have the same interface as the component they wrap, they are transparent for the client code&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt; which never has to know that it’s dealing with a decorator. This allows us to pass them around in place of the wrapped object which makes it possible to compose behaviors using as many decorators as we like. The following example shows how to compose the behavior for computing the price of a coffee with milk and cream&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/4f183053c117a6b9ad08d873f6b34551.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After applying the &lt;a href=&quot;https://refactoring.com/catalog/replaceSuperclassWithDelegate.html&quot;&gt;Replace Inheritance with Delegation&lt;/a&gt; refactoring we get to a design that uses composition instead of inheritance to create all the combinations of supplements and beverages. This fixes the &lt;strong&gt;Combinatorial Explosion&lt;/strong&gt; code smell.&lt;/p&gt;

&lt;figure style=&quot;overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverages_kata_decorators_refactoring.png&quot; alt=&quot;files after refactoring introducing the decorator design pattern&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Code after refactoring introducing the decorator design pattern.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You can have a look at the rest of the test after this refactoring in this &lt;a href=&quot;https://gist.github.com/trikitrok/223b064324a93957418f48a26557f3e8&quot;&gt;gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Then, we make the easy change. &lt;/h2&gt;

&lt;p&gt;Once we had the new design based in composition instead of inheritance in place, adding the requested feature is as easy as creating a new decorator that represents the cinnamon supplement pricing:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/bdb22d3d3b66408f4049deb3f27188fb.js&quot;&gt;&lt;/script&gt;

&lt;figure style=&quot;overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/solving_beverages_kata_decorators_for_supplements.png&quot; alt=&quot;code after adding the new feature&quot; /&gt;
&lt;figcaption&gt;&lt;em&gt;Code after adding the new feature.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Remember that using the initial design adding this feature would have involved multiplying by two the number of classes.&lt;/p&gt;

&lt;h2&gt;What have we gained and lost with this refactoring?&lt;/h2&gt;

&lt;p&gt;After the refactoring we have a new design that uses the decorator design pattern. This is a flexible alternative design to subclassing for extending behavior that allows us to add behavior dynamically to the objects wrapped by the decorators.&lt;/p&gt;

&lt;p&gt;Thanks to this runtime flexibility we managed to fix the &lt;strong&gt;Combinatorial Explosion&lt;/strong&gt; code smell and that made it easier to add the new feature. Now, instead of multiplying the number of classes by two, adding a new supplement only involves adding one new decorator class that represents the new supplement pricing. This new design makes the client code &lt;a href=&quot;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&quot;&gt;open-closed&lt;/a&gt; to the axis of change of adding new supplements.&lt;/p&gt;

&lt;p&gt;On the flip side, we have introduced some complexity&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt; related to creating the different compositions of decorators and components. At the moment this complexity is being managed by the client code (notice the chains of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt;s in the tests snippets above).&lt;/p&gt;

&lt;p&gt;There’s also something else that we have lost in the process. In the initial design only some combinations of beverages and supplements were allowed. This fact was encoded in the initial inheritance hierarchy. Now with our decorators we can dynamically add any possible combination of beverages and supplements.&lt;/p&gt;

&lt;p&gt;All in all, we think that the refactoring leaves us in a better spot because we’ll be likely required to add new supplements, and there are usual improvements we can make to the design to isolate the client code from the kind of complexity we have introduced.&lt;/p&gt;

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

&lt;p&gt;We have shown an example of preparatory refactoring to make easier the addition of a new feature, and learned about the &lt;strong&gt;Combinatorial Explosion&lt;/strong&gt; code smell and how to fix it using the decorator design pattern to get a new design in which we have protected the client code&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt; against variations involving new supplements.&lt;/p&gt;

&lt;p&gt;In a future post we will show how to encapsulate the creation of the different compositions of decorators and components using builders and/or factories to hide that complexity from client code, and show how we can limit again the allowed combinations that are part of the menu.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;I’d like to thank the WTM study group, and especially &lt;a href=&quot;https://twitter.com/InmaCNavas&quot;&gt;Inma Navas&lt;/a&gt; for solving this kata with me.&lt;/p&gt;

&lt;p&gt;Thanks to my Codesai colleagues and Inma Navas for reading the initial drafts and giving me feedback and and to &lt;a href=&quot;https://www.pexels.com/@fotios-photos&quot;&gt;Lisa Fotios&lt;/a&gt; for her picture.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] This and the next header come from &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt;’s quote:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“For each desired change, make the change easy (warning: this may be hard), then make the easy change”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] You can find this code smell described in &lt;a href=&quot;https://xp123.com/articles/&quot;&gt;Bill Wake&lt;/a&gt;’s wonderful &lt;a href=&quot;https://www.goodreads.com/book/show/337298.Refactoring_Workbook&quot;&gt;Refactoring Workbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] In this context &lt;strong&gt;variant&lt;/strong&gt; means a variation in behavior. For instance, each derived class in a hierarchy is a &lt;strong&gt;variant&lt;/strong&gt; of the base class.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Have a look at the chapter devoted to the decorator design pattern in the great &lt;a href=&quot;https://www.goodreads.com/book/show/58128.Head_First_Design_Patterns&quot;&gt;Head First Design Patterns&lt;/a&gt;. It’s the most didactic and fun explanation of the pattern I’ve ever found. This kata is heavily inspired in the example used in that chapter to explain the pattern.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] We could have also solved this problem composing functions instead of objects, but we wanted to practice with objects in this solution of the kata. That might be an interesting exercise for another practice session.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] In this context &lt;strong&gt;client code&lt;/strong&gt; means code that uses objects implementing the interface that both the components and decorators implement, which in the kata would correspond to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Beverage&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Also known as a “cortado leche y leche” in &lt;a href=&quot;https://en.wikipedia.org/wiki/Gran_Canaria&quot;&gt;Gran Canaria&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Complexity is most often the price we pay for flexibility. That’s why we should always assess  if the gains are worth the price.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] &lt;strong&gt;Protected variations&lt;/strong&gt; is another way to refer to the open-closed principle. I particularly prefer that way to refer to this design principle because I think it is expressed in a way that relates less to object orientation. Have a look at &lt;a href=&quot;https://en.wikipedia.org/wiki/Craig_Larman&quot;&gt;Craig Larman&lt;/a&gt;’s great article about it: &lt;a href=&quot;https://martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variation: The Importance of Being Closed&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/2019/04/beverages_prices_kata&quot;&gt;The Beverages Prices Refactoring kata: a kata to practice refactoring away from an awful application of inheritance&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/manuel-rivero-54411271/&quot;&gt;Manuel Rivero&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://refactoring.com/catalog/replaceSuperclassWithDelegate.html&quot;&gt;Replace Inheritance with Delegation&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/ieeeSoftware/protectedVariation.pdf&quot;&gt;Protected Variation: The Importance of Being Closed&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Craig_Larman&quot;&gt;Craig Larman&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&quot;&gt;Open-closed Principle&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/337298.Refactoring_Workbook&quot;&gt;Refactoring Workbook&lt;/a&gt;, &lt;a href=&quot;https://xp123.com/articles/&quot;&gt;William C. Wake&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/58128.Head_First_Design_Patterns&quot;&gt;Head First Design Patterns&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Eric_Freeman_(writer)&quot;&gt;Eric Freeman&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Kathy_Sierra&quot;&gt;Kathy Sierra&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/bertbates?lang=en&quot;&gt;Bert Bates&lt;/a&gt;, &lt;a href=&quot;https://www.elisabethrobson.com/&quot;&gt;Elisabeth Robson&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
          <pubDate>2020-11-30T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/11/solving-beverages-kata-1</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/11/solving-beverages-kata-1</guid>
        </item>
      
    
      
        <item>
          <title>Testeando una integración con S3</title>
          <description>&lt;p&gt;En uno de nuestros clientes actuales estamos ayudando en el desarrollo de un nuevo sistema que utiliza servicios de Amazon Web Services. Nos gustaría contarles el enfoque de testing que hemos seguido al integrarnos con S3, combinando tests locales contra imágenes Docker con tests en producción que se ejecutan periódicamente. Algunos de los tests que hemos hecho o el enfoque que hemos seguido lo hemos basado en los artículos de &lt;a href=&quot;https://twitter.com/copyconstruct&quot;&gt;Cindy Sridharan&lt;/a&gt; sobre testing de microservicios y testing en producción.&lt;/p&gt;

&lt;h2 id=&quot;nuestra-primera-feature-con-s3&quot;&gt;Nuestra primera feature con S3&lt;/h2&gt;

&lt;p&gt;Una de las primeras features que hemos tenido que desarrollar ha sido la subida de imágenes, como por ejemplo para el perfil de usuario. Decidimos utilizar S3 (&lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Simple Storage Service&lt;/a&gt;) para almacenar las imágenes que suben los usuarios. Por lo tanto, necesitamos integrarnos con S3 y una base de datos, para almacenar la información de usuario con la ruta a la imagen.&lt;/p&gt;

&lt;p&gt;Hacer los tests contra la base de datos suele ser bastante sencillo. Utilizamos una imagen de Docker oficial que simula la base de datos que usamos en producción, &lt;a href=&quot;https://hub.docker.com/_/mariadb/&quot;&gt;MariaDB&lt;/a&gt;. En este caso, haríamos tests contra el repositorio de usuarios que se conectaría con este contenedor. Usar esta imagen, aunque no sea “real”, nos da bastante confianza (por ser una imagen oficial) de que será muy similar al sistema real. Los tests serían del estilo “guardo esto en base de datos, le pido al repositorio que lo lea y compruebo que ha leído lo que guardé”.&lt;/p&gt;

&lt;p&gt;En el caso de S3, nos gustaría poder hacer lo mismo. Subo una imagen a S3 a través de un servicio que implementamos nosotros y compruebo que la imagen está disponible. Sin embargo, en el caso de los servicios de AWS, no contábamos (al menos hasta donde sabíamos) con imágenes oficiales soportadas por AWS. Se nos ocurrieron dos opciones para testear la integración con S3:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Hacer los tests de integración contra un bucket real de S3.&lt;/p&gt;

    &lt;p&gt;Así nos aseguramos que usamos la API correctamente. Pero trae una serie de problemas, como que es un gasto extra en la factura de AWS y hay que tener en cuenta que se pueden pisar recursos compartidos si hay tests que ejecutan varias personas a la vez.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Usar contenedores no oficiales que simulan S3.&lt;/p&gt;

    &lt;p&gt;No hay recursos compartidos entre distintos desarrolladores y es gratis, pero corres el riesgo de que la imagen se desactualice o tengas configuraciones distintas en producción.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;nuestro-primer-test-para-conectar-con-s3&quot;&gt;Nuestro primer test para conectar con S3&lt;/h2&gt;

&lt;p&gt;Para empezar optamos por usar una imagen Docker que simula S3, &lt;a href=&quot;https://hub.docker.com/r/adobe/s3mock/&quot;&gt;adobe/s3mock&lt;/a&gt;, en nuestros tests. Para ello, teníamos que configurar nuestro cliente de S3 para que apunte al endpoint de nuestro contenedor Docker e inyectarlo a nuestro servicio:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/7a5cdee1f9da50827e7314f69ff2a3ab.js?file=setup.php&quot;&gt;&lt;/script&gt;

&lt;p&gt;De esta forma el test de S3 queda muy sencillo. Lo único que hace es subir un fichero y comprobar que está disponible cuando intentamos descargarlo.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/7a5cdee1f9da50827e7314f69ff2a3ab.js?file=upload.php&quot;&gt;&lt;/script&gt;

&lt;p&gt;Luego hicimos otro test para comprobar que el borrado de imágenes funcionaba.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/rubendm92/7a5cdee1f9da50827e7314f69ff2a3ab.js?file=remove.php&quot;&gt;&lt;/script&gt;

&lt;p&gt;Suponiendo que la imagen de Docker se comporta igual que el S3 real, estos tests validan que usamos la API de S3 correctamente.&lt;/p&gt;

&lt;p&gt;Sin embargo, algunos miembros del equipo no estaban del todo cómodos testeando únicamente en una imagen “falsa” de S3. Para mejorar el grado de confianza en los tests  decidimos duplicar el test de subida de imágenes pero apuntado a un bucket de S3 real en AWS. De esta forma nuestra suite de test contiene tests para todas las posibles casuísticas contra la imagen de Docker de S3, y un único test contra el entorno real que nos sirve para comprobar que el sistema ha sido configurado correctamente.&lt;/p&gt;

&lt;h2 id=&quot;local-rara-vez-se-parece-a-staging-o-producción&quot;&gt;Local rara vez se parece a staging o producción&lt;/h2&gt;

&lt;p&gt;Creíamos que estos tests nos daban la tranquilidad de de que todo iba a funcionar perfectamente. Sin embargo, cuando el equipo de sistemas nos pidió cambiar el bucket en el que guardábamos imágenes en el entorno de staging y producción, vimos que no era así.&lt;/p&gt;

&lt;p&gt;Para asegurarnos de que no romperíamos nada al hacer ese cambio, decidimos hacer tests de configuración en producción porque este tipo de cambios de configuración suele ser más peligrosos que los cambios de código.&lt;/p&gt;

&lt;p&gt;Estos “tests” se ejecutan con el código ya en producción, pero con una feature flag que nos permite ocultar los cambios a los usuarios. Por eso se denominan &lt;strong&gt;tests en la fase de deploy&lt;/strong&gt;: el código está desplegado, pero aún no se ha “liberado” a los usuarios.&lt;/p&gt;

&lt;figure style=&quot;max-height:600px; max-width:600px; overflow: hidden; margin:auto;&quot;&gt;
    &lt;img src=&quot;/assets/test-types.jpeg&quot; alt=&quot;Cindy Sridharan&apos; types of tests&quot; /&gt;
    &lt;figcaption&gt;&lt;em&gt;Diferentes tipos de test de acuerdo al post de testing en producción de Cindy Sridharan.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Utilizamos dos variables de entorno distintas para apuntar al bucket viejo y el nuevo. Metimos una feature flag que decidía qué variable usar y desplegamos. Activamos la feature flag en staging y, sorpresa, empezaron a fallar las subidas de imágenes.&lt;/p&gt;

&lt;p&gt;Habíamos asumido que los tests contra la imagen de Docker era posible que dieran un falso positivo pero, ¿y el test que teníamos contra el bucket real?&lt;/p&gt;

&lt;p&gt;Resulta que nos estábamos conectando, mediante credenciales de un usuario de &lt;a href=&quot;https://aws.amazon.com/es/iam/&quot;&gt;IAM&lt;/a&gt;, a un bucket creado en el entorno de staging. En un punto, sistemas decidió cambiar esta forma de acceso porque no era una opción segura en producción, y pasamos a asignar permisos a través de un perfil a los pods de Kubernetes.&lt;/p&gt;

&lt;p&gt;Con este cambio nuestros tests seguían funcionando, aunque el sistema en producción estaba roto. Los tests que se ejecutaban contra la imagen de S3 pasaban porque no apuntaban al sistema real, mientras que el test que apuntaba a un bucket real de S3 pasaba porque se conectaba de una forma distinta.&lt;/p&gt;

&lt;p&gt;En este punto nos planteamos, ¿qué valor nos estaba aportando el test “real” si no se conectaba a S3 de la misma forma que se usaba en producción?&lt;/p&gt;

&lt;p&gt;Concluimos que ninguno, así que tomamos la decisión de borrar el test que teníamos contra el entorno real de AWS y mantener solo los tests contra la imagen de Docker. De esta forma, sólo teníamos testeado si nuestra forma de interactuar  con S3 era correcta, pero volvíamos a tener el inconveniente de quedar expuestos a posibles errores al cambiar la forma de establecer esa comunicación.&lt;/p&gt;

&lt;p&gt;Cuantas más piezas tiene nuestro sistema más fácil es que alguna de ellas falle y necesitamos mecanismos que nos ayuden a detectar esos errores lo antes posible. Tener tests que ejecutamos en local o en una pipeline, o un entorno de staging para testear nos ayudan a reducir esos riesgos. Sin embargo, aunque pueden ser una muy buena imitación de la realidad, no dejan de ser sino una especie de placebo que nos da seguridad de que no se romperá en producción.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I’m more and more convinced that staging environments are like mocks - at best a pale imitation of the genuine article and the worst form of confirmation bias. &lt;br /&gt;&lt;br /&gt;It’s still better than having nothing - but “works in staging” is only one step better than “works on my machine”.&lt;/p&gt;&amp;mdash; Cindy Sridharan (@copyconstruct) &lt;a href=&quot;https://twitter.com/copyconstruct/status/974530841190608897?ref_src=twsrc%5Etfw&quot;&gt;March 16, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;testeando-en-producción&quot;&gt;Testeando en producción&lt;/h2&gt;

&lt;p&gt;Ahora mismo, todos los tests se ejecutan en una pipeline que verifica que nuestro código es válido y, si lo es, se despliega en un entorno de staging. Esto nos protege de errores que hayamos cometido a la hora de programar pero, ¿qué pasa si por un error de configuración dejamos de tener acceso a ciertos recursos como puede ser base de datos o S3?&lt;/p&gt;

&lt;p&gt;Independientemente del equipo que gestione los recursos de infraestructura, lo normal es que la configuración de esos recursos esté en un repositorio con un ritmo de cambio distinto y con unos tests que no tienen porqué cubrir todos nuestros casos de uso. Alguien podría borrar los permisos de acceso a un recurso para una aplicación, desplegar y no enterarnos hasta que empezamos a recibir errores de los usuarios.&lt;/p&gt;

&lt;p&gt;La solución por la que hemos optado es chequear contínuamente en producción (y staging) que nuestro sistema tenga acceso a los recursos que necesita. Para ello, usamos un endpoint de health check. &lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt; llama periódicamente a este endpoint y, en lugar de simplemente devolver un OK para decir que nuestra API está funcionando, aprovechamos para realizar una serie de comprobaciones adicionales. Por volver un poco a la terminología de Cindy, estaríamos haciendo &lt;strong&gt;tests release&lt;/strong&gt; o post-release, ya que el código ya está disponible para los usuarios pero seguimos monitoreando posibles errores.&lt;/p&gt;

&lt;p&gt;En el caso de S3, lo que haremos es subir una pequeña imagen, comprobar que si le hacemos una request nos da un 200 y luego borrarla. Esto nos da la seguridad de que en todo momento nuestra API tiene acceso a S3 en producción. No evitará que se produzcan errores en producción, pero sí  nos avisará rápidamente del error, dando la posibilidad de que lo arreglemos incluso antes de que lo vean los usuarios.&lt;/p&gt;

&lt;h2 id=&quot;distintos-tests-distintos-beneficios&quot;&gt;Distintos tests, distintos beneficios&lt;/h2&gt;

&lt;p&gt;Resumiendo todo nuestro “viaje” hacia la tranquilidad de la integración con S3, al final, nos hemos quedado con tres tipos de tests.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tests de integración locales contra una imagen de Docker&lt;/strong&gt;. Son tests relativamente rápidos que nos dan la tranquilidad de que usamos el SDK de AWS de la forma correcta, y que se van a ejecutar en cada pipeline. Nos pueden proteger de subir a producción errores como URLs mal generadas o subir ficheros sin permisos de lectura o sin las cabeceras adecuadas.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tests de configuración cuando haya que hacer cambios&lt;/strong&gt; (config tests en fase de deploy). Si tenemos que cambiar la forma de conectarnos al bucket (o cambiar de bucket), duplicamos las configuraciones y decidimos una u otra en función de una feature flag. No nos protege de desplegar código con errores en producción, pero podemos desactivar ese código y volver a una configuración que funciona correctamente.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Health check de conexión con S3&lt;/strong&gt; (monitoring en fase de release o post-release). Es un test que se ejecutará periódicamente en staging y producción que comprobará que seguimos pudiendo hablar con S3 y que tenemos los permisos necesarios. No va a evitar que subamos errores a producción o que algún usuario pueda ver esos errores, pero tendremos una forma rápida de detectar esos errores y poder actuar en consecuencia.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;agradecimientos&quot;&gt;Agradecimientos&lt;/h2&gt;

&lt;p&gt;Gracias a mis compañeros de Codesai por el feedback y al equipo de B2B de LifullConnect por las conversaciones que han servido para escribir este post.&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/@copyconstruct/testing-microservices-the-sane-way-9bb31d158c16&quot;&gt;Testing microservices the sane way&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/copyconstruct&quot;&gt;Cindy Sridharan&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://medium.com/@copyconstruct/testing-in-production-the-safe-way-18ca102d0ef1&quot;&gt;Testing in production the safe way&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/copyconstruct&quot;&gt;Cindy Sridharan&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2020-10-28T16:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/10/testing-s3</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/10/testing-s3</guid>
        </item>
      
    
      
        <item>
          <title>Sleeping is not the best option</title>
          <description>&lt;h2&gt;Introduction. &lt;/h2&gt;

&lt;p&gt;Some time ago we were developing a code that stored some data with a given &lt;a href=&quot;https://en.wikipedia.org/wiki/Time_to_live&quot;&gt;TTL&lt;/a&gt;. We wanted to check not only that the data was stored correctly but also that it expired after the given TTL. This is an example of testing asynchronous code.&lt;/p&gt;

&lt;p&gt;When testing asynchronous code we need to carefully coordinate the test with the system it is testing to avoid running the assertion before the tested action has completed&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. For example, the following test will always fail because the assertion in line 30 is checked before the data has expired:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9643d3e99e9ed3ef362cfab3055c4be6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In this case the test always fails but in other cases it might be worse, failing intermittently when the system is working, or passing when the system is broken. We need to make the test wait to give the action we are testing time to complete successfully and fail if this doesn’t happen within a given timeout period.&lt;/p&gt;

&lt;h2&gt;Sleeping is not the best option.&lt;/h2&gt;
&lt;p&gt;This is an improved version of the previous test in which we are making the test code wait before the checking that the data has expired to give the code under test time to run:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/22abb9f0148f94f50081a9672d3b50ea.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The problem with the simple sleeping approach is that in some runs the timeout might be enough for the data to expire but in other runs it might not, so the test will fail intermittently; it becomes a flickering test. Flickering tests are confusing because when they fail, we don’t know whether it’s due to a real bug, or it is just a false positive. If the failure is relatively common, the team might start ignoring those tests which can mask real defects and completely destroy the value of having automated tests.&lt;/p&gt;

&lt;p&gt;Since the intermittent failures happen because the timeout is too close to the time the behavior we are testing takes to run, many teams decide to reduce the frequency of those failures by increasing the time each test sleeps before checking that the action under test was successful. This is not practical because it soon leads to test suites that take too long to run.&lt;/p&gt;

&lt;h2&gt;Alternative approaches. &lt;/h2&gt;

&lt;p&gt;If we are able to detect success sooner, succeeding tests will provide rapid feedback, and we only have to wait for failing tests to timeout. This is a much better approach than waiting the same amount of time for each test regardless it fails or succeeds.&lt;/p&gt;

&lt;p&gt;There are two main strategies to detect success sooner: &lt;strong&gt;capturing notifications&lt;/strong&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; and &lt;strong&gt;polling for changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the case we are using as an example, polling was the only option because redis didn’t send any monitoring events we could listen to.&lt;/p&gt;

&lt;h2&gt;Polling for changes. &lt;/h2&gt;
&lt;p&gt;To detect success as soon as possible, we’re going to probe several times separated by a time interval which will be shorter than the previous timeout. If the result of a probe is what we expect the test pass, if the result we expect is not there yet, we sleep a bit and retry. If after several retries, the expected value is not there, the test will fail.&lt;/p&gt;

&lt;p&gt;Have a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkThatDataHasExpired&lt;/code&gt; method in the following code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0c9316696bedea68ccfd60dc00039bff.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;By polling for changes we avoid always waiting the maximum amount of time. Only in the worst case scenario, when consuming all the retries without detecting success, we’ll wait as much as in the just sleeping approach that used a fixed timeout.&lt;/p&gt;

&lt;h2&gt;Extracting a helper.&lt;/h2&gt;

&lt;p&gt;Scattering ad hoc low level code that polls and probes like the one in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkThatDataHasExpired&lt;/code&gt; throughout your tests not only make them difficult to understand, but also is a very bad case of duplication. So we extracted it to a helper so we could reuse it in different situations.&lt;/p&gt;

&lt;p&gt;What varies from one application of this approach to another are &lt;strong&gt;the probe&lt;/strong&gt;, &lt;strong&gt;the check&lt;/strong&gt;, &lt;strong&gt;the number of probes before failing&lt;/strong&gt; and &lt;strong&gt;the time between probes&lt;/strong&gt;, everything else we extracted to the following helper&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/688b3f850ab4459dbdcba06170f4e34a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is how the previous tests would look after using the helper:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ffef6ac252fc819b0a65cd49d189222b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice that we’re passing the probe, the check, the number of probes and the sleep time between probes to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsyncTestHelpers::assertWithPolling&lt;/code&gt; function.&lt;/p&gt;

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

&lt;p&gt;We showed an example in Php of an approach to test asynchronous code described by &lt;a href=&quot;https://www.higherorderlogic.com/&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;http://www.natpryce.com/&quot;&gt;Nat Pryce&lt;/a&gt; in their &lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt; book. This approach avoids flickering test and produces much faster test suites than using a fixed timeout. We also showed how we abstracted this approach by extracting a helper function that we are reusing in our code.&lt;/p&gt;

&lt;p&gt;We hope you’ve found this approach interesting. If you want to learn more about this and several other techniques to effectively test asynchronous code, have a look at the wonderful &lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt; book&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;Thanks to my Codesai colleagues for reading the initial drafts and giving me feedback and to &lt;a href=&quot;https://www.pexels.com/@tottster&quot;&gt;Chrisy Totty&lt;/a&gt; for the lovely cat picture.&lt;/p&gt;

&lt;h2&gt;Notes.&lt;/h2&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] This is a nice example of &lt;i&gt;Connascence of Timing (CoT)&lt;/i&gt;. &lt;i&gt;CoT&lt;/i&gt; happens when when the timing of the execution of multiple components is important. In this case the action being tested must run before the assertion that checks its observable effects. That&apos;s the coordination we talk about. Check &lt;a href=&quot;https://codesai.com/2017/01/about-connascence&quot;&gt;our post about Connascence&lt;/a&gt; to learn more about this interesting topic.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] In the &lt;i&gt;capturing notifications&lt;/i&gt; strategy the test code &quot;observes the system by listening for events that the system sends out. An event-based assertion waits for an event by blocking on a monitor until gets notified or times out&quot;, (from &lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests book&lt;/a&gt;).&lt;br /&gt; 

  Some time ago we developed &lt;a href=&quot;https://gist.github.com/trikitrok/a39f5fbec6ab0ee0c6f8db68e87a552c#file-async-test-tools-cljs&quot;&gt;some helpers using the &lt;i&gt;capturing notifications&lt;/i&gt; strategy &lt;/a&gt;to test asynchronous ClojureScript code that was using &lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt; channels. Have a look at, for instance, the &lt;code class=&quot;highlighter-rouge&quot;&gt;expect-async-message&lt;/code&gt; assertion helper in which we use &lt;code class=&quot;highlighter-rouge&quot;&gt;core.async/alts!&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;core.async/timeout&lt;/code&gt; to implement this behaviour. The &lt;code class=&quot;highlighter-rouge&quot;&gt;core.async/alts!&lt;/code&gt; function selects the first channel that responds. If that channel is the one the test code was observing we assert that the received message is what we expected. If the channel that responds first is the one generated by &lt;code class=&quot;highlighter-rouge&quot;&gt;core.async/timeout&lt;/code&gt; we fail the test. We mentioned these &lt;code class=&quot;highlighter-rouge&quot;&gt;async-test-tools&lt;/code&gt; in previous post: &lt;a href=&quot;https://codesai.com/2017/06/testing-om-components&quot;&gt;Testing Om components with cljs-react-test&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Have a look at the &lt;a href=&quot;https://github.com/npryce/goos-code-examples/tree/master/testing-asynchronous-systems&quot;&gt;testing asynchronous systems examples&lt;/a&gt; in the &lt;a href=&quot;https://github.com/npryce/goos-code-examples&quot;&gt;GOOS Code examples repository&lt;/a&gt; for a more object-oriented implementation of helper for the &lt;i&gt;polling for changes&lt;/i&gt; strategy, and also examples of the &lt;i&gt;capturing notifications&lt;/i&gt; strategy.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Chapter 27, &lt;i&gt;Testing Asynchronous code&lt;/i&gt;, contains a great explanation of the two main strategies to test asynchronous code effectively: &lt;i&gt;capturing notifications&lt;/i&gt; and &lt;i&gt;polling for changes&lt;/i&gt;.
&lt;/div&gt;

&lt;h2&gt;References.&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;, &lt;a href=&quot;https://www.higherorderlogic.com/&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;http://www.natpryce.com/&quot;&gt;Nat Pryce&lt;/a&gt; (chapter 27: &lt;i&gt;Testing Asynchronous Code&lt;/i&gt;)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/nonDeterminism.html#footnote-useful-nondeterminism&quot;&gt;Eradicating Non-Determinism in Tests&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
          <pubDate>2020-10-17T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/10/polling-and-probing</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/10/polling-and-probing</guid>
        </item>
      
    
      
        <item>
          <title>The value of caring</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;We’d like to tell you about a narrative that has been very useful for us in the coaching work we have been doing with several teams during the last year.&lt;/p&gt;

&lt;h2 id=&quot;origin&quot;&gt;Origin&lt;/h2&gt;

&lt;p&gt;It all started during a consultancy work that &lt;a href=&quot;https://twitter.com/jvalduvieco?lang=en&quot;&gt;Joan Valduvieco&lt;/a&gt; and I did at the beginning of 2019 at &lt;a href=&quot;https://en.wikipedia.org/wiki/Trovit&quot;&gt;Trovit&lt;/a&gt;. &lt;a href=&quot;https://www.linkedin.com/in/josecgil/&quot;&gt;José Carlos Gil&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/eduardmateu/&quot;&gt;Edu Mateu&lt;/a&gt; had brought us to help Trovit’s B2B team. We spent a week with the team asking questions, observing their work and doing some group dynamics to try to understand how we might help them.&lt;/p&gt;

&lt;p&gt;After that week of “field work” we had gathered a ton of notes, graphs and insights that we needed to put in order and analyze. This is always a difficult task because it is about analyzing a sociotechnical system (team, knowledge, technology, existing code, organization, pressure, changes,…) which is a complex system in constant flux. In a way, you have to accept that this is something you can’t wholly understand, and even less in a short period of time.&lt;/p&gt;

&lt;p&gt;Having that in mind, we tried to do our best to get a first approximation by representing the different dynamics and processes we had observed in several &lt;a href=&quot;https://en.wikipedia.org/wiki/Causal_loop_diagram&quot;&gt;causal loop diagrams&lt;/a&gt;. This work helped us clarify our minds and highlight how habits, knowledge, beliefs, culture and practices were creating vicious cycles, (related to some positive feedback loops in the causal loop diagram&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;), that were amplifying and preserving destructive effects for the team and its software which made their system less habitable and sustainable, and created inefficiencies and loss of value.&lt;/p&gt;

&lt;p&gt;After that we started to think about strategies that might break those vicious cycles, either by reducing the effect of some node (a problematic habit, practice or belief), by removing an interaction between nodes in a positive loop, or introducing negative feedback in the system (new practices and habits) to stabilize it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Donella_Meadows&quot;&gt;Donella H. Meadows&lt;/a&gt; in her book &lt;a href=&quot;https://www.goodreads.com/book/show/3828902-thinking-in-systems&quot;&gt;Thinking in Systems: A Primer&lt;/a&gt; talks about different types of &lt;a href=&quot;https://en.wikipedia.org/wiki/Twelve_leverage_points&quot;&gt;leverage points&lt;/a&gt; which are places within a complex system where you can try to apply what we call &lt;strong&gt;change levers&lt;/strong&gt; to make the system evolve from its current dynamics into another that might be more interesting for the team.&lt;/p&gt;

&lt;figure style=&quot;max-height:600px; max-width:600px; overflow: hidden; margin:auto;&quot;&gt;
    &lt;img src=&quot;/assets/caring_change_leverage_points.png&quot; alt=&quot;Donella H. Meadows&apos; types of leverage points and their relative strength&quot; /&gt;
    &lt;figcaption&gt;&lt;em&gt;Different types of leverage points and their relative strength according to Meadows.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We detected several &lt;strong&gt;change levers&lt;/strong&gt; that might be applied to the system at different leverage points  to improve the sustainability of the system, such as, “Improving Technical Skills”, “Knowledge Diffusion”, “Knowledge Crystallization”, “Changing Habits”, “All Team Product Owning” or “Remote First”&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All of them attacked vicious cycles that were entrenched in the team’s dynamics, and were valuable in themselves, but we were not sure that they would be enough to change the system’s current dynamics. Something that we observed during our field work was that the team was very skeptical about the probabilities of success of any initiative to improve its situation. They had gone through several failed attempts of “Agile” transformation before, and this has left them in a kind of state of learned helplessness. Why had those previous attempts failed? Would ours succeed using our &lt;strong&gt;change levers&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;We started to realize that there was a deeper force at play that was exacerbating the rest of the problems and would reduce the effect of any of the other &lt;strong&gt;change levers&lt;/strong&gt;. We realized that they would be useless unless the team had enough slack and company support to apply them. The deeper and stronger force that was inhibiting the possibility of having that slack and support was the very conception of what value meant for the company, it was a cultural problem.&lt;/p&gt;

&lt;div style=&quot;max-height:350px; max-width:350px; overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/caring_drucker-on-culture.png&quot; alt=&quot;Drucker:  Culture eats strategy for breakfast&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;We then came up with a new &lt;strong&gt;change lever&lt;/strong&gt;: “Redefinition of Value”. This was the most powerful &lt;strong&gt;change lever&lt;/strong&gt; of all the ones we had detected because it was a cultural change&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;, and it would increase the probabilities of success of all other &lt;strong&gt;change levers&lt;/strong&gt;. Being a cultural change also made it  the most difficult to apply.&lt;/p&gt;

&lt;h2 id=&quot;redefinition-of-value&quot;&gt;Redefinition of Value&lt;/h2&gt;

&lt;p&gt;What was this “Redefinition of Value” &lt;strong&gt;change lever&lt;/strong&gt; about?&lt;/p&gt;

&lt;p&gt;The culture of the team was understanding value only as producing features for their clients as quickly as possible. This definition of value only includes certain kinds of tasks, the ones that directly produce features, but excludes many tasks that don’t directly produce features, but that are necessary for the sustainability of the system (the business and team) itself. The first kind of work is called productive work and the second kind is called caring work&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Believing that only one type of work has value, (productive work), and then focusing only on that type of work is an extractive micro-optimization that might end destabilizing the system&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;max-width:550px; overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/caring_traditional_model.png&quot; alt=&quot;Model biased to productive work&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The redefinition of value we proposed was that not only producing features for the client as quickly as possible is valuable, that there is also value in keeping the sustainability of the business and team. Aside from working on productive tasks, you need to devote energy and time to work on caring tasks which are concerned with keeping the health of the ecosystem composed of the code, the team and the client, so that it can continue evolving, being habitable for the team and producing value. We think that this kind of work (caring work) has value and is strategic for a company. If you think about it, at the bottom, this is about seeing the team as the real product and establishing a healthier and more durable relationship with clients.&lt;/p&gt;

&lt;p&gt;This idea of caring work comes from economic studies from a gender perspective. In feminist economics caring work is defined as, “those occupations that provide services that help people develop their capabilities, or the ability to pursue the aspects of their lives that they value” or “necessary occupations and care to sustain life and human survival”.&lt;/p&gt;

&lt;p&gt;We thought that for this redefinition of value to be successful, it needed to be stated very clearly to the team from above. This clarity is crucial to avoid the developers having to solve the conflicts that arise when the value of caring tasks is not clear. In those cases, it’s often caring work which gets neglected.&lt;/p&gt;

&lt;p&gt;Those conflicts are actually strategic and, as such, they should be resolved at the right level so that the team receives a clear message that gives them focus, and the peace of mind that they are always working in something that is really valued by the company.&lt;/p&gt;

&lt;p&gt;In many companies the value of caring only appears in company statements (corporate language), but it’s not part of the real culture, the real system of values of the company. This situation creates  a kind of doublespeak that might be very harmful. A way to avoid that might be putting your money where your mouth is.&lt;/p&gt;

&lt;p&gt;So with all these ingredients we cooked a presentation for the team lead, the CTO and the CPO of the company&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;, to tell them the strategy we would like to follow, the cultural change involved in the redefinition of value that we thought necessary and how we thought that the possible conflicts between the two types of work should be resolved at their level. They listened to us and decided to try. They were very brave and this decision enabled a wonderful change in the team we started to work with&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;. The success of this experiment made it possible for other teams to start experimenting with this redefinition of value as well.&lt;/p&gt;

&lt;h2 id=&quot;is-this-not-the-metaphor-of-technical-debt-in-a-different-guise8&quot;&gt;Is this not the metaphor of technical debt in a different guise?&lt;a href=&quot;#nota8&quot;&gt;&lt;sup&gt;[8]&lt;/sup&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;We think that the narrative of caring work, it’s not equivalent to technical debt.&lt;/p&gt;

&lt;p&gt;The technical debt metaphor has evolved a lot from the concept that &lt;a href=&quot;https://en.wikipedia.org/wiki/Ward_Cunningham&quot;&gt;Ward Cunningham&lt;/a&gt; originally coined. With time the metaphor was extended to cover more than what he initially meant&lt;a href=&quot;#nota9&quot;&gt;&lt;sup&gt;[9]&lt;/sup&gt;&lt;/a&gt;. This extended use of the metaphor has been criticized by some software practitioners&lt;a href=&quot;#nota10&quot;&gt;&lt;sup&gt;[10]&lt;/sup&gt;&lt;/a&gt;. Leaving this debate aside, let’s focus on how most people currently understand the technical debt metaphor:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;“Design or implementation constructs that are expedient in the short term but that set up a technical context that can make a future change more costly or impossible. Technical debt is a contingent liability whose impact is limited to internal systems qualities - primarily, but not only, maintainability and evolvability.” from &lt;a href=&quot;https://www.goodreads.com/book/show/42778944-managing-technical-debt&quot;&gt;Managing Technical Debt: Reducing Friction in Software Development&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Technical debt describes technical problems that cause friction in software development and how to manage them.&lt;/p&gt;

&lt;p&gt;On the other hand, the caring work narrative addresses the wider concern of sustainability in a software system, considering all its aspects (social, economic and technical), and how both productive and caring work are key to keep a sustainable system. We think that makes the caring work narrative a wider concept than technical debt.&lt;/p&gt;

&lt;p&gt;This narrative has created a cultural shift that has allowed us not only to manage technical debt better, but also to create room for activities directed to prevent technical debt, empower the team, amplify its knowledge, attract talent, etc. We think that considering caring work as valuable as productive work placed us in a plane of dialogue which was more constructive than the financial metaphor behind technical debt.&lt;/p&gt;

&lt;div&gt;
&lt;img src=&quot;/assets/caring_redefining_value.png&quot; alt=&quot;Redefinition of value&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;how-are-we-applying-it-at-the-moment&quot;&gt;How are we applying it at the moment?&lt;/h2&gt;

&lt;p&gt;Applying the caring work narrative depends highly on the context of each company. Please, do not take this as a “a recipe for applying caring work” or “the way to apply caring work”. What is important is to understand the concept, then you will have to adapt it to your own context.&lt;/p&gt;

&lt;p&gt;In the teams we coach we are using something called caring tasks (descriptions of caring work) along with a variation of the concerns mechanism&lt;a href=&quot;#nota11&quot;&gt;&lt;sup&gt;[11]&lt;/sup&gt;&lt;/a&gt; and devoting percentages of time in every iteration to work on caring tasks. The developers are the ones that decide which caring work is needed. 
These decisions are highly contextual and they involve trade offs related to asymmetries initially found in each team and in their evolution. There are small variations in each team, and the way we apply them in each team has evolved over time. You can listen about some of those variations in the two podcasts that &lt;a href=&quot;https://thebigbranchtheorypodcast.github.io/&quot;&gt;The Big Branch Theory Podcast&lt;/a&gt; will devote to this topic.&lt;/p&gt;

&lt;p&gt;We plan to write in the near future another post about how we are using the concerns mechanism in the context of caring work.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;We have been using the redefinition of value given by the caring work for more than a year now. Its success in the initial team made it possible for other teams to start experimenting with it as well. Using it in new teams has taught us many things and we have introduced local variations to adapt the idea to the realities of the new teams and their coaches.&lt;/p&gt;

&lt;p&gt;So far, it’s working for us well and we feel that it has helped us in some aspects in which using the technical debt metaphor is difficult like, for example, improving processes or owning the product.&lt;/p&gt;

&lt;p&gt;Some of the teams worked only on legacy systems, and other teams worked on both greenfield and legacy systems (all the legacy systems had, and still have, a lot of technical debt).&lt;/p&gt;

&lt;p&gt;We think it is important to consider that the teams we have been collaborating with were in a context of extraction&lt;a href=&quot;#nota12&quot;&gt;&lt;sup&gt;[12]&lt;/sup&gt;&lt;/a&gt; in which there is already a lot of value to protect.&lt;/p&gt;

&lt;div style=&quot;max-width:350px; overflow: hidden; margin:auto;&quot;&gt;
&lt;img src=&quot;/assets/caring_3x_model.jpeg&quot; alt=&quot;3X model&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Due to the coronavirus crisis some of the teams have started to work on an exploration context. This is a challenge and we wonder how the caring work narrative evolves in this context and a scarcity scenario.&lt;/p&gt;

&lt;p&gt;To finish we’d like to add a quote from Lakoff&lt;a href=&quot;#nota13&quot;&gt;&lt;sup&gt;[13]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;“New metaphors are capable of creating new understandings and, therefore, new realities”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We think that the caring work narrative might help create a reality in which both productive and caring work are valued and more sustainable software systems are more likely.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Thanks to  &lt;a href=&quot;https://twitter.com/jvalduvieco?lang=en&quot;&gt;Joan Valduvieco&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/zigiella&quot;&gt;Beatriz Martín&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/nesiaran&quot;&gt;Vanesa Rodríguez&lt;/a&gt; for all the stimulating conversations that lead to the idea of applying the narrative of caring work in software development.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/josecgil/&quot;&gt;José Carlos Gil&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/eduardmateu/&quot;&gt;Edu Mateu&lt;/a&gt; for inviting us to work with &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt;. It has been a great symbiosis so far.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/marcsturlese/&quot;&gt;Marc Sturlese&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/hernanjaviercastagnola/&quot;&gt;Hernán Castagnola&lt;/a&gt; for daring to try.&lt;/p&gt;

&lt;p&gt;Thanks to Lifull’s B2B and B2C teams and all the Codesai colleagues that have worked with them, for all the effort and great work to take advantage of the great opportunity that caring tasks created.&lt;/p&gt;

&lt;p&gt;Finally, thanks to my Codesai colleagues and to &lt;a href=&quot;https://rachelcarmena.github.io/&quot;&gt;Rachel M. Carmena&lt;/a&gt; for reading the initial drafts and giving me feedback.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Positive in this context does not mean something good. The feedback is positive because it makes the magnitude of the perturbation increase (it positively retrofeeds it).&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Those were the names we used when we presented what we have learned during the consultancy.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] In systems thinking a &lt;strong&gt;leverage point&lt;/strong&gt; is a place within a complex system (a corporation, an economy, a living body, a city, an ecosystem) where a shift can be applied to produce changes in the whole system behavior. It would be a low &lt;strong&gt;leverage point&lt;/strong&gt; if a small shift produces a small behavioral change. It’s a high &lt;strong&gt;leverage point&lt;/strong&gt; if a small shoif causes a large behavioral change. According to &lt;a href=&quot;https://en.wikipedia.org/wiki/Donella_Meadows&quot;&gt;Donella H. Meadows&lt;/a&gt; the most effective place to intervene a system is:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;“The mindset or paradigm out of which the system — its goals, power structure, rules, its culture — arises”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can imagine this is the most difficult thing to change as well. To know more read &lt;a href=&quot;http://donellameadows.org/archives/leverage-points-places-to-intervene-in-a-system/&quot;&gt;Leverage Points: Places to Intervene in a System&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Also known as reproductive work. This idea comes from a gender perspective of economics. You can learn more about it reading the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Care_work&quot;&gt;Care work&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Feminist_economics&quot;&gt;Feminist economics&lt;/a&gt; articles in Wikipedia.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Sadly we observe this phenomena at all scales: a business, a relationship, an ecosystem, the planet…&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] &lt;a href=&quot;https://www.linkedin.com/in/eduardmateu/&quot;&gt;Edu Mateu&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/marcsturlese/&quot;&gt;Marc Sturlese&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/hernanjaviercastagnola/&quot;&gt;Hernán Castagnola&lt;/a&gt; were then the B2B team lead, the CTO and the CPO, respectively.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] B2B was the first team we worked with. &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; and I started coaching them in February 2019 but after a couple of months &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt; and 
&lt;a href=&quot;https://twitter.com/mjtordesillas&quot;&gt;Manuel Tordesillas&lt;/a&gt; joined us. Thanks to their great work of this team, other teams started using the caring work narrative around 6 month after.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota8&quot;&gt;&lt;/a&gt; [8] Thanks to &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/AlfredoCasado&quot;&gt;Alfredo Casado&lt;/a&gt; for the interesting discussions about technical debt that helped me write this part.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota9&quot;&gt;&lt;/a&gt; [9] You can listen &lt;a href=&quot;https://en.wikipedia.org/wiki/Ward_Cunningham&quot;&gt;Ward Cunningham&lt;/a&gt; himself explaining what he actually meant with the technical debt metaphor in this &lt;a href=&quot;https://www.youtube.com/watch?v=pqeJFYwnkjE&quot;&gt;video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota10&quot;&gt;&lt;/a&gt; [10] Two examples: &lt;a href=&quot;https://sites.google.com/site/unclebobconsultingllc/a-mess-is-not-a-technical-debt&quot;&gt;A Mess is not a Technical Debt&lt;/a&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_C._Martin&quot;&gt;Robert C. Martin&lt;/a&gt; and &lt;a href=&quot;https://www.higherorderlogic.com/2010/07/23/bad-code-isnt-technical-debt-its-an-unhedged-call-option/&quot;&gt;Bad code isn’t Technical Debt, it’s an unhedged Call Option&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/sf105?lang=en&quot;&gt;Steve Freeman&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota11&quot;&gt;&lt;/a&gt; [11] The concerns mechanism is described by  &lt;a href=&quot;https://twitter.com/XaV1uzz&quot;&gt;Xavi Gost&lt;/a&gt; in his talk &lt;a href=&quot;https://www.youtube.com/watch?v=pp8j1ggCaoM&quot;&gt; CDD (Desarrollo dirigido por consenso)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota12&quot;&gt;&lt;/a&gt; [12] To know more watch &lt;a href=&quot;https://www.youtube.com/watch?v=YGhS8VQpS6s&quot;&gt;3X Explore/Expand/Extrac&lt;/a&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; or read &lt;a href=&quot;https://ideas.riverglide.com/3x-explore-expand-extract-b9aad6402a5a&quot;&gt;Kent Beck’s 3X: Explore, Expand, Extract&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/AntonyMarcano&quot;&gt;Antony Marcano&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/AndyPalmer&quot;&gt;Andy Palmer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota13&quot;&gt;&lt;/a&gt; [13] From &lt;a href=&quot;https://www.goodreads.com/book/show/34459.Metaphors_We_Live_By&quot;&gt;Metaphors We Live By&lt;/a&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/George_Lakoff&quot;&gt;George Lakoff&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Mark_Johnson_(philosopher)&quot;&gt;Mark Johnson&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;h3 id=&quot;books&quot;&gt;Books&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/34459.Metaphors_We_Live_By&quot;&gt;Metaphors We Live By&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/George_Lakoff&quot;&gt;George Lakoff&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://en.wikipedia.org/wiki/Mark_Johnson_(philosopher)&quot;&gt;Mark Johnson&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/3828902-thinking-in-systems&quot;&gt;Thinking in Systems: A Primer&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Donella_Meadows&quot;&gt;Donella H. Meadows&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/123715.Slack&quot;&gt;Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Tom_DeMarco&quot;&gt;Tom Demarco&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf&quot;&gt;Patterns of Software: Tales from the Software Community&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_P._Gabriel&quot;&gt;Richard P. Gabriel&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/144724.Filters_against_Folly&quot;&gt;Filters against Folly: How to Survive despite Economists, Ecologists, and the Merely Eloquent&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Garrett_Hardin&quot;&gt;Garrett Hardin&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/42778944-managing-technical-debt&quot;&gt;Managing Technical Debt: Reducing Friction in Software Development&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Philippe_Kruchten&quot;&gt;Philippe Kruchten&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/robert-nord-3553548/&quot;&gt;Robert Nord&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/ipekozkaya/&quot;&gt;Ipek Ozkaya&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;articles&quot;&gt;Articles&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://donellameadows.org/archives/leverage-points-places-to-intervene-in-a-system/&quot;&gt;Leverage Points: Places to Intervene in a System
&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Donella_Meadows&quot;&gt;Donella H. Meadows&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Positive_feedback&quot;&gt;Positive feedback (or exacerbating feedback)&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://donellameadows.org/archives/leverage-points-places-to-intervene-in-a-system/&quot;&gt;Leverage points places to intervene in a system&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Twelve_leverage_points&quot;&gt;Twelve leverage points&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Care_work&quot;&gt;Care work&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Feminist_economics&quot;&gt;Feminist economics&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/System_dynamics&quot;&gt;System Dynamics&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Causal_loop_diagram&quot;&gt;Causal loop diagram&lt;/a&gt; (Wikipedia)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/TechnicalDebt.html&quot;&gt;Technical Debt&lt;/a&gt;, &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://sites.google.com/site/unclebobconsultingllc/a-mess-is-not-a-technical-debt&quot;&gt;A Mess is not a Technical Debt&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_C._Martin&quot;&gt;Robert C. Martin&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.higherorderlogic.com/2010/07/23/bad-code-isnt-technical-debt-its-an-unhedged-call-option/&quot;&gt;Bad code isn’t Technical Debt, it’s an unhedged Call Option&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/sf105?lang=en&quot;&gt;Steve Freeman&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ideas.riverglide.com/3x-explore-expand-extract-b9aad6402a5a&quot;&gt;Kent Beck’s 3X: Explore, Expand, Extract&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/AntonyMarcano&quot;&gt;Antony Marcano&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/AndyPalmer&quot;&gt;Andy Palmer&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;talks&quot;&gt;Talks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=B31QrNFyRyc&quot;&gt;Code Blindness&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mfeathers&quot;&gt;Michael Feathers&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=XL_lOoomRTA&quot;&gt;A Philosophical Look at System Dynamics&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Donella_Meadows&quot;&gt;Donella H. Meadows&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=pqeJFYwnkjE&quot;&gt;Explanation of original debt metaphor&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Ward_Cunningham&quot;&gt;Ward Cunningham&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YGhS8VQpS6s&quot;&gt;3X Explore/Expand/Extract&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=pp8j1ggCaoM&quot;&gt;CDD (Desarrollo dirigido por consenso)&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/XaV1uzz&quot;&gt;Xavi Gost&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
          <pubDate>2020-06-11T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/06/caring</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/06/caring</guid>
        </item>
      
    
      
        <item>
          <title>SPIDR, criterios para dividir historias de usuario</title>
          <description>&lt;p&gt;Las historias de usuarios son una gran herramienta para entender lo que se quiere hacer, por qué y para quién. Ron Jeffries en el libro Extreme Programming Installed, describe los tres aspectos críticos de las historias de usuario como &lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;Card, Conversation, Confirmation&lt;/a&gt;, dónde la tarjeta (Card) simplemente recoge el texto suficiente para que podamos tener una conversación más adelante. Dicho de otro modo, &lt;strong&gt;una historia de usuario es el recordatorio de una conversación.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;La diferencia con la captura de requisitos clásica, es que los requisitos intentan expresar todos los detalles de manera escrita. Las historias de usuario en cambio buscan obtener esa información mediante una conversación en el &lt;strong&gt;momento preciso.&lt;/strong&gt; Ese momento será cuando quede poco para que la historia de usuario sea abordada.&lt;/p&gt;

&lt;p&gt;Uno de los típicos problemas cuando se escriben las historias de usuarios es mantener conversaciones largas y complejas. Esto es probablemente un síntoma de que el tamaño de la historia de usuario abarca demasiados temas. Otro problema común suele producirse más adelante, cuando se tarda mucho en que los usuarios dispongan de la funcionalidad derivada de la historia de usuario, este problema también puede ser causado por el tamaño de las historias.&lt;/p&gt;

&lt;p&gt;El arte de crear historias de usuario de tamaño adecuado por tanto es esencial para sacar partido a todo su potencial.&lt;/p&gt;

&lt;p&gt;Existen diferentes heurísticas que nos ayudan a detectar y resolver problemas con el tamaño de las historias de usuario. Bill Wake y Mike Cohn tienen un trabajo interesante al respecto. En este articulo nos centraremos en un conjunto de heurísticas que Mike Cohn propuso para partir historias de usuario, y que denominó &lt;strong&gt;SPIDR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SPIDR&lt;/strong&gt; es el acrónimo de &lt;strong&gt;Spike, Paths, Interfaces, Data and Rules,&lt;/strong&gt; que son en realidad una serie de criterios por los que potencialmente podríamos partir una historia de usuario.&lt;/p&gt;

&lt;h2 id=&quot;spike&quot;&gt;&lt;strong&gt;Spike&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Algunas veces las historias son demasiado grandes porque el equipo no sabe cómo hacer alguna parte de la historia. Quizás la historia envuelve una tecnología no familiar o una parte del código desconocida. Lo mejor en esto casos es hacer un spike para reducir incertidumbre. &lt;strong&gt;Un spike es una actividad de investigación&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Un ejemplo podría ser:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro, cualquier click es analizado por el Super Sistema de Marketing Automatizado para que pueda recibir un email con información sobre cosas en las que yo parezca estar interesado.&lt;/div&gt;

&lt;p&gt;Y al reconocer que nadie conoce cómo funciona el Super Sistema de Marketing Automatizado y puede haber mucha incertidumbre, pasaríamos a crear el siguiente spike&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Investigar el Super Sistema de Marketing Automatizado.&lt;/div&gt;

&lt;p&gt;Un spike debe tener un timebox para evitar la tentación de parálisis por análisis.&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,228,242);color: #434648; padding-left:5px&quot;&gt;El objetivo de un spike es el aprendizaje, no el desarrollo de una funcionalidad. Los spikes ayudan a reducir incertidumbre sobre cómo construir la funcionalidad. Por otro lado, crear spikes con demasiada frecuencia puede ser un síntoma de que el equipo necesita formación en aspectos concretos (tecnología, dominio, etc).&lt;/div&gt;

&lt;h2 id=&quot;paths&quot;&gt;Paths&lt;/h2&gt;

&lt;p&gt;A veces se puede considerar que una historia tiene múltiples pasos. El usuario hace X y entonces hace Y y entonces Z. Un ejemplo podría ser:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt; Como miembro, puedo pagar por una reserva que he realizado.&lt;/div&gt;

&lt;p&gt;De la que podemos sacar los siguientes pasos convertidos en historias de usuario:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro reservando un coche, puedo introducir la información del pago.&lt;/div&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro reservando un coche, puedo introducir la dirección de facturación.&lt;/div&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro reservando un coche, puedo indicar la oficina en la que recogeré el coche reservado.&lt;/div&gt;

&lt;p&gt;Las diferentes historias en las que se divide la historia original son independientes y por tanto, si quisiesemos podríamos implementarlas en paralelo. O podríamos optar por realizar una primera release en el que alguno de los caminos sea aún manual.&lt;/p&gt;

&lt;p&gt;Por ejemplo, se le podría avisar al usuario que para la parte relativa a “emitir la factura” debe enviar un correo con sus datos fiscales. Posteriormente este correo es respondido por una persona de manera manual hasta que el sistema implemente la generación de la factura.&lt;/p&gt;

&lt;h2 id=&quot;interfaces&quot;&gt;Interfaces&lt;/h2&gt;

&lt;p&gt;Algunas historias de usuario son complicadas porque tienen múltiples interfaces. A veces pueden ser &lt;em&gt;user interfaces&lt;/em&gt; (mobile, desktop) y otras &lt;em&gt;data interfaces&lt;/em&gt; (múltiples APIs).&lt;/p&gt;

&lt;p&gt;Si tuviéramos una historia que necesita que funcione en la web, en iOs y Android, una buena opción es partir por tipo de interface, Ejemplo:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como un usuario de iOS, puedo hacer cualquier cosa.&lt;/div&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como un usuario de Android, puedo hacer cualquier cosa.&lt;/div&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como un usuario usando un browser, puedo hacer cualquier cosa.&lt;/div&gt;

&lt;h2 id=&quot;data&quot;&gt;Data&lt;/h2&gt;

&lt;p&gt;Una historia puede ser larga por la cantidad y tipos de datos que debe soportar. Desarrollar una versión inicial que soporte un subset de datos puede ser una gran modo de partir una historia.&lt;/p&gt;

&lt;p&gt;También podríamos decidir ignorar algunos tipos de datos de manera eventual. Ignorarlos puede pasar por no coleccionarlos o no procesarlos o validarlos.&lt;/p&gt;

&lt;p&gt;Un ejemplo podría ser:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como turista quiero ver cosas interesantes en la ciudad.&lt;/div&gt;

&lt;p&gt;Podríamos partir la historia de acuerdo con los diferentes tipos de “cosas interesantes”, en este caso, museos, tours, actividades, etc.&lt;/p&gt;

&lt;h2 id=&quot;rules&quot;&gt;Rules&lt;/h2&gt;

&lt;p&gt;Algunas historias de usuario son largas porque implican implementar múltiples reglas. Un ejemplo sería:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro, puedo reservar un coche
	&lt;ul&gt;
    &lt;li&gt;Un miembro no puede reservar un coche con más de 90 días de antelación.&lt;/li&gt;
   &lt;li&gt;Un miembro no puede tener más de 3 reservas activas a la vez.&lt;/li&gt;
  &lt;/ul&gt;
 &lt;/div&gt;

&lt;p&gt;Que se podría partir atacando alguna regla en una historia de usuario diferente:&lt;/p&gt;

&lt;div style=&quot;background: rgb(251,243,219);color: #434648; padding-left:5px&quot;&gt;Como miembro, no puedo tener más de 3 reservas activas a la vez&lt;/div&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h2&gt;

&lt;p&gt;Manejar el tamaño preciso de las historias de usuario nos ofrece ventajas para entregar funcionalidad de manera temprana y focalizarnos en pequeños aspectos de valor. Conocer heurísticas para partir las historias de usuario nos ayuda a visualizar formas de hacerlo. Aunque existen múltiples propuestas a este problema, SPIDR de Mike Cohn ofrece un conjunto simple, fácil de recordar y que nos puede ayudar bastante en la mayoría de los escenarios.&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/extreme-programming-installed/0201708426/&quot;&gt;Extreme Programming Installed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ronjeffries.com/xprog/articles/expcardconversationconfirmation/&quot;&gt;Essential XP: Card, Conversation, Confirmation By Ron Jeffries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.notion.so/franreyes/SPIDR-criterios-para-dividir-USs-8de76d0d06fd4b15b8639a47e4dac8b4#143be6c2ddc648108b7730a55a4a238e&quot;&gt;F&lt;/a&gt;&lt;a href=&quot;https://www.mountaingoatsoftware.com/blog/five-simple-but-powerful-ways-to-split-user-stories&quot;&gt;ive Simple but Powerful Ways to Split User&lt;/a&gt; &lt;a href=&quot;https://www.notion.so/franreyes/SPIDR-criterios-para-dividir-USs-8de76d0d06fd4b15b8639a47e4dac8b4#143be6c2ddc648108b7730a55a4a238e&quot;&gt;Stories&lt;/a&gt; By Mike Cohn&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.mountaingoatsoftware.com/better-user-stories/&quot;&gt;Better User Stories Course&lt;/a&gt; By Mike Cohn&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://xp123.com/articles/twenty-ways-to-split-stories/&quot;&gt;Twenty Ways to Split Stories&lt;/a&gt; By Bill Wake&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2020-05-10T16:48:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/05/spidr</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/05/spidr</guid>
        </item>
      
    
      
        <item>
          <title>¡Habemus podcast!</title>
          <description>&lt;p&gt;Haciendo caso omiso de todas las recomendaciones sanitarias para este confinamiento hemos decidido, como podréis adivinar por el título, ¡crear un podcast!&lt;/p&gt;

&lt;p&gt;La realidad es que ya llevábamos tiempo con ganas de hacerlo y estas últimas fechas no han sido más que la excusa perfecta para encontrar el tiempo que en otras ocasiones no habíamos sido capaces de encontrar. En este podcast hablaremos de los temas que más nos interesan en el mundo que nos apasiona: el desarrollo de software.&lt;/p&gt;

&lt;p&gt;Las temáticas no estarán restringidas a ninguna tecnología concreta; intentaremos hablar de temas transversales como por ejemplo buenas prácticas, testing, arquitectura, aprendizaje, nuestro amigo el legacy code y otros muchos. No hablaremos mucho de lenguajes/librerías/frameworks concretos más allá de cuando esto nos sirva para ejemplificar alguna práctica más transversal, 
que es lo más nos motiva.&lt;/p&gt;

&lt;p&gt;Este podcast no es un podcast sólo de Codesai, está abierto a que cualquiera con ganas 
y algo que decir tenga un espacio para participar. Así que si queréis participar o tenéis un tema del que os gustaría que hablásemos no tenéis más que decirlo.&lt;/p&gt;

&lt;p&gt;El nombre, decidido bajo arduo consenso y discusiones interminables de 10 minutos o más, 
es &lt;strong&gt;The Big Branch Theory&lt;/strong&gt;. Para el quien no pille la tontería, pensad en Trunk Based Development, una práctica de la que hemos hablado en muchas ocasiones… sí, ese es el nivel jaja.&lt;/p&gt;

&lt;p&gt;De momento llevamos ya 3 capítulos publicados donde hablamos sobre pair programing, microservicios, y aprendizje, así variadito para empezar. Y como estaréis ya ansios@s, sin más preámbulo podéis escucharlos a continuación:&lt;/p&gt;

&lt;p&gt;Podeís agregar el &lt;a href=&quot;https://anchor.fm/s/56e0f78/podcast/rss&quot;&gt;feed del podcast&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O simplemente escucharlo a continuación:&lt;/p&gt;

&lt;iframe src=&quot;https://open.spotify.com/embed-podcast/episode/0dUvwkecs5vZGXzxjW5rfZ&quot; width=&quot;100%&quot; height=&quot;232&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot; allow=&quot;encrypted-media&quot;&gt;&lt;/iframe&gt;

&lt;iframe src=&quot;https://open.spotify.com/embed-podcast/episode/75wJbJ4vSmrySMfNBrBVK9&quot; width=&quot;100%&quot; height=&quot;232&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot; allow=&quot;encrypted-media&quot;&gt;&lt;/iframe&gt;

&lt;iframe src=&quot;https://open.spotify.com/embed-podcast/episode/66xV3t7JXTsuEFTfHPiM1b&quot; width=&quot;100%&quot; height=&quot;232&quot; frameborder=&quot;0&quot; allowtransparency=&quot;true&quot; allow=&quot;encrypted-media&quot;&gt;&lt;/iframe&gt;
</description>
          <pubDate>2020-05-08T09:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/05/habemus_podcast</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/05/habemus_podcast</guid>
        </item>
      
    
      
        <item>
          <title>¡Bienvenido a Codesai, Rubén!</title>
          <description>&lt;p&gt;Contamos hoy con una buena noticia, bien recibida dada la situación actual, y es que a partir de ahora somos uno más en Codesai! Queríamos escribir un pequeño post dándole la bienvenida a Rubén, presentándole un poquito desde mi perspectiva y luego la suya.&lt;/p&gt;

&lt;p&gt;En su día, junto con Rubén organizamos algunas de las primeras katas y charlas que hicimos en la comunidad de Gran Canaria. Y luego nos volvimos locos y junto con el resto de organizadores montamos el Socracan en Gran Canaria en 2016, que siguió en 2017, 18 y 19 hasta que volvió a Tenerife este año 2020.&lt;/p&gt;

&lt;p&gt;Alfredo, Migue y yo pudimos trabajar con Rubén durante más de un año, y no dudamos del valor que puede aportar a un equipo. Consideramos que posee un gran nivel técnico (traducción: es fleje bueno), no tiene miedo a meterse en cualquier área del desarrollo y se alinea mucho con los principios que compartimos en Codesai. En un plano más personal, siempre ha demostrado ser una persona dispuesta a ayudar y a buscar la forma de llegar a acuerdos razonables.&lt;/p&gt;

&lt;p&gt;Por lo que en conjunto, hacía ya un tiempo que lo habíamos valorado como un buen candidato para formar parte de Codesai. Y sin enrollarme mucho más, voy a dejar que se presente él mismo un poquito :)
Un placer tenerte con nosotros Rubén!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/incorporacion_ruben_handshake.png&quot; alt=&quot;Rubén&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;photo-footer&quot;&gt;Nos remitimos a una foto que hicimos de coña hace un año. Un pequeño &quot;edit&quot; y listo, Rubén nunca llegó a sospechar nada ;)&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Gracias a Dani y todo el equipo por la calurosa bienvenida. Probablemente no se me conozca tanto en la comunidad como a otros, así que aquí va un poco sobre mí.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Llevo trabajando en esto del desarrollo algo más de 5 años. Alguna gente diría que soy fullstack, pero a mi me gusta más la expresión “soy capaz de meter deuda técnica en varias capas del sistema”.
Me encanta trabajar en entornos en los que se siguen prácticas de eXtreme Programming, colaborando con negocio para aportar valor y aprendiendo todo lo posible del resto de personas con las que trabajo.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hará unos 6 años que conozco a varios miembros de Codesai. Desde 2014 nos juntábamos Miguel, Ronny, Dani y yo para hacer katas, a las que a veces se nos unía gente como Manu Rivero, Alfredo o Fran. También nos cruzamos en muchos eventos de desarrollo, en los que conocí a Toño y Manu Tordesillas.
Son gente con la que comparto inquietudes y sus posts/charlas siempre han sido referencia para mí en el aprendizaje.
He hablado con Miguel y Dani en alguna ocasión para unirme a Codesai, hasta que finalmente surgió la oportunidad en febrero de este año (justo en el momento de mayor estabilidad laboral, ¿eh?).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sólo me queda dar las gracias a todo el equipo por acogerme y esperemos que dentro de no mucho podamos hacer un Flejesai presencial y compartir unos días juntos.&lt;/em&gt;&lt;/p&gt;
</description>
          <pubDate>2020-04-17T17:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/04/bienvenido-ruben</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/04/bienvenido-ruben</guid>
        </item>
      
    
      
        <item>
          <title>El valor de escribir el test primero</title>
          <description>&lt;p&gt;Toda persona que haya investigado un poco el Test Driven Development estará familiarizada con los 3 pasos que implica:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;span style=&quot;color: red&quot;&gt;Red&lt;/span&gt;, escribir primero un test que falla&lt;/li&gt;
  &lt;li&gt;&lt;span style=&quot;color: limegreen&quot;&gt;Green&lt;/span&gt;, escribir el código de producción para pasar el test&lt;/li&gt;
  &lt;li&gt;&lt;span style=&quot;color: blue&quot;&gt;Refactor&lt;/span&gt;, evaluar una posible mejora en la implementación&lt;/li&gt;
  &lt;li&gt;Y repetimos indefinidamente hasta obtener funcionalidades completas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si bien es cierto que marcan la base del TDD, si nos quedamos ahí no estamos sino arañando la superficie.
A medida que lo practicamos y adquirimos fluidez, vamos descubriendo el gran valor que nos aporta seguir estos pasos (o posibles variaciones), pues tienen su razón de ser y a menudo no se aprecia si no le dedicamos el tiempo y la atención suficientes.&lt;/p&gt;

&lt;div style=&quot;display: flex; justify-content: center; margin: 10px 0&quot;&gt;
    &lt;img style=&quot;max-width: 600px&quot; src=&quot;/assets/charla_dani_cas2019.png&quot; alt=&quot;Dani CAS 2019&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;He querido desarrollar una charla para hacer hincapié en varios argumentos sobre el por qué de escribir el test primero, en lugar de hacerlo de forma automática puesto que simplemente se trata del primer paso a seguir en el ciclo. También quise ilustrar algunos de esos argumentos con ejemplos de live coding para que se pudiera (espero) apreciar cómo el ser consciente de éstos afecta al flujo de desarrollo. Y sobretodo, intentar que se recuerde el siguiente mensaje:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;TDD = Diseñar&lt;/li&gt;
  &lt;li&gt;Escribir el test primero = Pensar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tuve la oportunidad de presentarla en esta pasada CAS 2019, y ahora se puede ver en el enlace a continuación.&lt;/p&gt;

&lt;p&gt;Muchas gracias a la organización de la CAS 2019, a Autentia por la producción del vídeo, y a toda persona que haya apreciado la charla :)&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;nS1gqqf6Cb0&quot;&gt;
    &lt;div data-id=&quot;nS1gqqf6Cb0&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/nS1gqqf6Cb0/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Las slides se pueden &lt;a href=&quot;https://www.slideshare.net/DanielOjedaLoisel/tdd-no-es-escribir-el-test-primero&quot;&gt;ver en Slideshare&lt;/a&gt;&lt;/p&gt;
</description>
          <pubDate>2020-02-16T14:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2020/02/el-valor-de-escribir-el-test-primero</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2020/02/el-valor-de-escribir-el-test-primero</guid>
        </item>
      
    
      
        <item>
          <title>Me vuelvo a Subversion!</title>
          <description>&lt;p&gt;Estaba el otro día viendo la charla &lt;a href=&quot;https://vimeo.com/338843900&quot;&gt;Continuous delivery and the theory of constraints&lt;/a&gt; de Steve Smith, que de paso os recomiendo, y en un momento de la charla el autor relatando una experiencia pasada en un equipo que usaba subversion en lugar de git u otro DVCS, decía algo como:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sometimes bad tools lead to good practices and sometimes good tools lead to very bad practices&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esto me hizo pararme un poco a pensar si realmente con los DVCS, que podríamos decir que se han instalado como un estándar de facto en la industria, hemos ganado tanto o incluso que cosas hemos perdido por el camino.&lt;/p&gt;

&lt;h1 id=&quot;cómo-elegimos-nuestro-vcs&quot;&gt;¿Cómo elegimos nuestro VCS?&lt;/h1&gt;

&lt;p&gt;Voy a dar por hecho que usar un VCS es algo conveniente en cualquier proyecto, aquí creo que no hay mucho debate. La cuestión es, ¿cuando nos planteamos que VCS usar qué criterios estamos siguiendo para escoger uno u otro?.&lt;/p&gt;

&lt;p&gt;Yo soy de la creencia de que las prácticas van primero y las herramientas después, primero tengo que tener claro qué prácticas quiero seguir, por ejemplo la integración continua, y después elijo las herramientas más simples que habiliten la aplicación de dichas prácticas.&lt;/p&gt;

&lt;p&gt;Siguiendo con la idea anterior, para mi la integración continua y en consecuencia la posibilidad de hacer deploy continuo, son prácticas que considero muy deseables. Aclarar que cuando me refiero a integración continua quiero decir integrar el trabajo en pequeños incrementos que se miden en minutos o en el peor de los casos en horas. Un escenario donde el trabajo que estoy haciendo ahora se vaya a integrar con el del resto del equipo en días o semanas queda lejos de la idea original de integración continua, aunque tenga dos jenkins y un travis.&lt;/p&gt;

&lt;p&gt;¿Y que necesito para esto?, pues poco más que un sistema que me permita ir integrando mis cambios en una línea de desarrollo, no necesito un VCS que me ofrezca un sistema muy sofisticado para crear/mezclar/rebasar ramas como ofrecen muchos DVCS.&lt;/p&gt;

&lt;p&gt;La reflexión que considero importante aquí es, &lt;strong&gt;¿estoy eligiendo la herramienta más simple que habilite mis prácticas?&lt;/strong&gt; o &lt;strong&gt;¿estoy dejando que mis prácticas se definan por el uso de una herramienta que ofrece más posibilidades?&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;commit-vs-commit--push&quot;&gt;Commit vs Commit &amp;amp; Push&lt;/h1&gt;

&lt;p&gt;Gestión de ramas aparte otra diferencia importante cuando usamos un DVCS es que para enviar cambios al repositorio que compartimos con todo el equipo no basta con hacer “commit” sino que después de añadir nuestros cambios al repositorio local tenemos que sincronizarlo con el repositorio compartido, por ejemplo en git haciendo push.&lt;/p&gt;

&lt;p&gt;Analizando un poco qué significa esto de &lt;strong&gt;&lt;em&gt;commit&lt;/em&gt;&lt;/strong&gt;, la acepción que más encaja con el uso que hacemos en nuestro contexto podría ser:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;transfer something to (a state or place where it can be kept or preserved)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En otras palabras, hacer commit es tomar la decisión de que nuestros cambios son suficientemente buenos como para querer guardarlos o preservarlos. En un VCS no distribuido como svn hacer commit requiere un alto grado de compromiso por parte del desarrollador ya que estamos tomando la decisión de que nuestros cambios son suficientemente buenos para considerar que añaden valor al producto e integrarlos con los cambios que están haciendo el resto de compañeros. &lt;strong&gt;En un DVCS sin embargo el grado de compromiso para hacer commit es mucho menor, ya que simplemente estamos guardando esos cambios en el repositorio local pero no estamos añadiendo ningún valor al producto ni integrándonos con los cambios del resto de compañeros, en este escenario el compromiso real es cuando hacemos push&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En git es incluso habitual hacer algún tipo de modificación sobre el commit o conjunto de commits previo al push, por ejemplo squash para juntar varios commits en uno sólo, de forma que ese grado de compromiso del que hablaba antes de hacer commit en git es casi nulo, porque antes de hacer push la herramienta nos ofrece multitud de opciones para rehacer esos commits a nuestro gusto. ¿Cuántas veces habéis hecho un commit con algo que sabéis que no está del todo terminado para “no perder los cambios”?, ¡un VCS no es un sistema de backup!. Si estás haciendo esto, salvo que acabes de recibir una llamada porque tu casa está en llamas, es muy probable que tus incrementos sean demasiado grandes.&lt;/p&gt;

&lt;p&gt;Lo que ocurre al final cuando dividimos nuestro proceso para integrar cambios en dos fases es lo mismo que ocurre cuando hacemos nuestros cambios sobre una rama para integrarlos posteriormente. Estamos retrasando nuestro compromiso, tomar compromisos es por supuesto algo difícil que no se puede hacer a la ligera, en general siempre que encontramos problemas difíciles o que pueden causar cierto dolor tenemos dos opciones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Retrasar el dolor en el tiempo, es humano e intuitivo retrasar las situaciones difíciles o que puedan causar cierto dolor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Hacerlo lo más frecuentemente posible, con el doble objetivo de por un lado minimizar el dolor dividiendo el problema en otros más pequeños y por otro lado aliviar el nivel de dificultad repitiendo el proceso muchas veces, con lo que vamos desarrollando las prácticas y la experiencia que nos permiten hacer de un problema difícil algo cotidiano y más sencillo.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El espíritu del desarrollo ágil siempre ha abogado por esta segunda opción: iteraciones cortas, integración continua o incluso TDD. Todas estas prácticas tienen por objetivo convertir situaciones dolorosas y difíciles en situaciones cotidianas y más sencillas de abordar.&lt;/p&gt;

&lt;p&gt;Dicho todo esto, &lt;strong&gt;para seguir las prácticas que realmente son importantes para mi no necesito de una herramienta que me permita aplazar el compromiso, es más, diría que es sano que la herramienta no disponga de esta opción y que todo el equipo se habitué como algo natural a que tomar compromisos es algo que hay que hacer con la mayor frecuencia posible y en las dosis más pequeñas posibles&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h1&gt;

&lt;p&gt;No es mi objetivo decirle a nadie qué herramienta tiene que usar, en realidad, la discusión sobre la herramienta a usar no es muy relevante. Lo importante, y ya que estamos en unas fechas tan propias para la reflexión a final de año, es que analicemos si la herramienta que estamos usando está alineada con nuestras prácticas y filosofía de desarrollo o si por el contrario nos hemos dejado cegar un poco por la cantidad de opciones que ofrece una herramienta y es precisamente esta última la que está definiendo las prácticas por nosotros.&lt;/p&gt;

</description>
          <pubDate>2019-12-28T09:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/12/me-vuelvo-a-svn</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/12/me-vuelvo-a-svn</guid>
        </item>
      
    
      
        <item>
          <title>Funny Docker Workshop to learn from scratch</title>
          <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;In one of our current clients we are taking some learning time for new things outside of our current context/stack. One of the proposals of the team was a Docker workshop because I introduced it for our CI and our local testing environments to avoid connecting to production from the local machines to run the our tests.&lt;/p&gt;

&lt;p&gt;So I was the person in charge of preparing it. And here I would like to share a way to learn Docker from scratch I thought of.&lt;/p&gt;

&lt;h1 id=&quot;learn-by-doing&quot;&gt;Learn by doing&lt;/h1&gt;

&lt;p&gt;I really believe in the philosophy for learning new things is tighly related with practice, practice, practice… And that’s also in Codesai’s DNA, so I wanted to ideate a way to explain a bit of theory of Docker and exercises to apply that theory. The theory I explained answers the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The whys:
    &lt;ul&gt;
      &lt;li&gt;Why Docker?&lt;/li&gt;
      &lt;li&gt;Differences with past technologies&lt;/li&gt;
      &lt;li&gt;Why is it better than the previous tooling?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The hows:
    &lt;ul&gt;
      &lt;li&gt;How does Docker solve these problems?&lt;/li&gt;
      &lt;li&gt;How does Docker improve upon the previous tooling?&lt;/li&gt;
      &lt;li&gt;How can Docker help us?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The small exercise consist on assembling two different applications with different languages and let people see one of the advantages of Docker. &lt;strong&gt;Removing the complexity of dedicated infrastructure&lt;/strong&gt; for a concrete language/stack.&lt;/p&gt;

&lt;p&gt;And as the last trick I wanted them to see how easy is to build, push an image and publish your Docker container in a famous service like Heroku. So in the last part of the workshop we do that. The steps explaining how to publish your app on Heroku can be also found on the README file inside of the &lt;em&gt;heroku/&lt;/em&gt; folder from the root of the repository.&lt;/p&gt;

&lt;p&gt;So I’d like you to check it yourself, give me some feedback and enjoy what I prepared. &lt;strong&gt;Let’s Dockerize everything!!&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is the repository with the content and the exercises. &lt;strong&gt;Each folder has a README.md&lt;/strong&gt; explaining what to do. The main README.md is just the theory of Docker. Enjoy! &lt;a href=&quot;https://github.com/Groxalf/docker-workshop&quot;&gt;Docker Workshop Repo&lt;/a&gt;&lt;/p&gt;

</description>
          <pubDate>2019-12-17T21:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/12/docker-workshop</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/12/docker-workshop</guid>
        </item>
      
    
      
        <item>
          <title>Playing Fizzbuzz with property-based testing</title>
          <description>&lt;h3&gt;Introduction. &lt;/h3&gt;

&lt;p&gt;Lately, I’ve been playing a bit with property-based testing.&lt;/p&gt;

&lt;p&gt;I practised doing the FizzBuzz kata in Clojure and used the following constraints for fun&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add one property at a time before writing the code to make the property hold.&lt;/li&gt;
  &lt;li&gt;Make the failing test pass before writing a new property.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;The kata step by step. &lt;/h3&gt;

&lt;p&gt;To create the properties, I partitioned the first 100 integers according to how they are transformed by the code. This was very easy using two of the operations on sets that Clojure provides (&lt;a href=&quot;https://clojuredocs.org/clojure.set/difference&quot;&gt;difference&lt;/a&gt; and &lt;a href=&quot;https://clojuredocs.org/clojure.set/intersection&quot;&gt;intersection&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The first property I wrote checks that the &lt;strong&gt;multiples of 3 but not 5 are Fizz&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2b0e460147bf47696ccc43b88faa49e9.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the code that makes that test pass:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/42efeec5462d2fe648e3b350bbd7b296.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Next, I wrote a property to check that the &lt;strong&gt;multiples of 5 but not 3 are Buzz&lt;/strong&gt; (I show only the new property for brevity):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c37f7776f2c2eaf18432d787d4d4d5fa.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the code that makes the new test pass:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/71418b2b09288af7006b7d2020db988b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then, I added a property to check that the &lt;strong&gt;multiples of 3 and 5 are FizzBuzz&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/657e3928f4d8f075d668870f658af801.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which was already passing with the existing production code.&lt;/p&gt;

&lt;p&gt;Finally, I added a property to check that the &lt;strong&gt;rest of numbers are just casted to a string&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3d3ee8ecd47cbffdb7f2073f974d8405.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which Id made pass with this version of the code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7976898dfdb2404c42e830699613fb84.js&quot;&gt;&lt;/script&gt;

&lt;h3&gt;The final result. &lt;/h3&gt;

&lt;p&gt;These are the resulting tests where you can see all the properties together:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/6f25524b46d5693d73580031a0f0d542.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;You can find &lt;a href=&quot;https://github.com/trikitrok/fizzbuzz-pbt&quot;&gt;all the code in this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Conclusions. &lt;/h3&gt;

&lt;p&gt;It was a lot of fun doing this kata. It is a toy example that didn’t make me dive a lot into &lt;a href=&quot;http://clojure.github.io/test.check/&quot;&gt;clojure.check’s generators documentation&lt;/a&gt; because I could take advantage of &lt;a href=&quot;https://clojure.github.io/clojure/clojure.set-api.html&quot;&gt;Clojure’s set functions&lt;/a&gt; to write the properties.&lt;/p&gt;

&lt;p&gt;I think the resulting properties are quite readable even if you don’t know Clojure. On the other hand, the resulting implementation is probably not similar to the ones you’re used to see, and it shows Clojure’s conciseness and expressiveness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] I&apos;m not saying that you should do property-based testing with this constraints. They probably make no sense in real cases. The constraints were meant to make doing the kata fun.
&lt;/div&gt;

</description>
          <pubDate>2019-07-29T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/07/fizzbuzz-pbt</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/07/fizzbuzz-pbt</guid>
        </item>
      
    
      
        <item>
          <title>La kata Gilded Rose en PL/SQL: escribiendo los tests</title>
          <description>&lt;h3&gt;Contexto. &lt;/h3&gt;

&lt;p&gt;En uno de nuestros actuales clientes, &lt;a href=&quot;http://www.mutuatfe.es/&quot;&gt;Mutua Tinerfeña&lt;/a&gt;, estamos trabajando diferentes técnicas para construir software de manera progresiva y confiable. Aunque el equipo es pequeño, sus miembros usan y conocen tecnologías muy diferentes, por lo que necesitábamos practicar dichas técnicas usando como vehículo un lenguaje que dominaran todos los miembros del equipo. Con esto podíamos evitar que algunos miembros del equipo tuvieran que aprender otros paradigmas para poder practicar las nuevas técnicas. Así que elegimos &lt;a href=&quot;https://en.wikipedia.org/wiki/PL/SQL&quot;&gt;PL/SQL&lt;/a&gt;, que era el lenguaje que todos tenían en común, como vehículo de aprendizaje.&lt;/p&gt;

&lt;p&gt;Este ejercicio es parte de un curso sobre refactoring de base de datos que estamos preparando con mucho amor. Este curso está pensado para equipos que trabajan con un legacy en el que la mayoría del código se encuentra en la base de datos y puedan incorporar técnicas como testing y empezar a trabajar su legacy con confianza y de forma más sostenible. Esta primera versión del curso está orientado fundamentalmente a Oracle como SGBD, aunque muchas de las ideas pueden ser trasladadas a otros SGBD como SQLServer.&lt;/p&gt;

&lt;h3&gt;Aprendiendo refactoring y TDD en PL/SQL&lt;/h3&gt;

&lt;p&gt;Una de las prácticas que hicimos fue resolver la &lt;a href=&quot;https://github.com/emilybache/GildedRose-Refactoring-Kata/tree/master/plsql&quot;&gt;kata Gilded Rose en PL/SQL&lt;/a&gt; para practicar refactoring y TDD. En esta kata lo primero que se debe hacer, antes de añadir la funcionalidad que nos piden, es cubrir el código de tests. Estos tests nos permiten refactorizar el código para hacer que, finalmente, sea fácil añadir la nueva funcionalidad usando TDD. En este post contaremos cómo escribimos los tests para la versión PL/SQL de la kata.&lt;/p&gt;

&lt;h3&gt;Testeando la kata Gilded Rose en PL/SQL usando utPSQL&lt;/h3&gt;

&lt;p&gt;La herramienta que usamos para testear el código PL/SQL fue &lt;a href=&quot;http://utplsql.org/about/&quot;&gt;utPSQL&lt;/a&gt; que es un framework de testing open-source para PL/SQL and SQL. utPSQL nos permite lanzar los tests de manera muy fácil.&lt;/p&gt;

&lt;p&gt;Para escribir los tests hay que crear un paquete&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. En la especificación del paquete hay que añadir una serie de anotaciones, y, por último, escribir el propio test en el cuerpo del paquete.&lt;/p&gt;

&lt;p&gt;Para lanzar todos los tests desde la base de datos&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; hay que hacer la siguiente llamada a la “librería”:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;begin ut.run(); end;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Esta llamada buscará en el schema todos los paquetes que contengan las anotaciones y lanzará sus tests. Existe también la posibilidad de lanzar sólo los tests de un determinado paquete indicándolo como un argumento.&lt;/p&gt;

&lt;p&gt;Estos son los tests para la kata Gilded Rose en PL/SQL:
&lt;script src=&quot;https://gist.github.com/franreyes/037db9310136bfdc189b42025ab77d93.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Aunque pueda parecer sorprendente, los tests resultantes son bastante legibles. La legibilidad de los tests, en comparación con otras librerías similares, es uno de los puntos a favor de utPSQL.&lt;/p&gt;

&lt;h3&gt;Conclusiones&lt;/h3&gt;
&lt;p&gt;Hemos visto como es posible hacer testing en PL/SQL usando utPSQL. Estos tests crearán una red de seguridad que nos permitirá refactorizar el código, o lo que es lo mismo, mejorar su diseño preservando su comportamiento.&lt;/p&gt;

&lt;p&gt;En el próximo post de esta serie enseñaremos como se pueden aplicar técnicas de refactoring y de diseño para mejorar el código PL/SQL de la kata Gilded Rose en pequeños pasos manteniendo los tests en verde en todo momento.&lt;/p&gt;

&lt;h3&gt;Agradecimientos&lt;/h3&gt;
&lt;p&gt;Me gustaría agradecer a mi compañero &lt;a href=&quot;https://twitter.com/trikitrok?lang=en&quot;&gt;Manuel Rivero&lt;/a&gt; por ayudarme a revisar y editar este post, y al equipo de Mutua Tinerfeña por las aportaciones ofrecidas desde su amplia experiencia en este entorno.&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
	&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Un paquete es una agrupación lógica de procedimientos, funciones, tipos, constantes, etc. Un paquete tiene 2 partes, una especificación y un cuerpo. La especificación es una interfaz para el consumidor y el cuerpo expone la implementación.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
	&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] También existe la posibilidad de lanzar los tests desde una términal, lo que permite vincularlos a un sistema de integración continua de manera muy sencilla.
&lt;/div&gt;
</description>
          <pubDate>2019-07-07T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/07/gilded-rose-plsql-tests</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/07/gilded-rose-plsql-tests</guid>
        </item>
      
    
      
        <item>
          <title>An example of listening to the tests to improve a design</title>
          <description>&lt;h3&gt;Introduction. &lt;/h3&gt;

&lt;p&gt;Recently in the B2B team at &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;LIFULL Connect&lt;/a&gt;, we improved the validation of the clicks our API receive using a service that detects whether the clicks were made by a bot or a human being.&lt;/p&gt;

&lt;p&gt;So we used TDD to add this new validation to the previously existing validation that checked if the click contained all mandatory information. This was the resulting code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/76c9082ae1a3add22e0695f92a658cbc.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and these were its tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/328f80a0c5c8cdc1cbe67e5ac4c51171.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The problem with these tests is that they know too much. They are coupled to many implementation details. They not only know the concrete validations we apply to a click and the order in which they are applied, but also details about what gets logged when a concrete validations fails. There are multiple axes of change that will make these tests break. The tests are fragile against those axes of changes and, as such, they might become a future maintenance burden, in case changes along those axes are required.&lt;/p&gt;

&lt;p&gt;So what might we do about that fragility when any of those changes come?&lt;/p&gt;

&lt;h3&gt;Improving the design to have less fragile tests. &lt;/h3&gt;

&lt;p&gt;As we said before the test fragility was hinting to a design problem in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; code. The problem is that it’s concentrating too much knowledge because it’s written in a procedural style in which it is querying every concrete validation to know if the click is ok, combining the result of all those validations and knowing when to log validation failures. Those are too many responsibilities for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; and is the cause of the fragility in the tests.&lt;/p&gt;

&lt;p&gt;We can revert this situation by changing to a more object-oriented implementation in which responsibilities are better distributed. Let’s see how that design might look:&lt;/p&gt;

&lt;h4&gt;1. Removing knowledge about logging.&lt;/h4&gt;

&lt;p&gt;After this change, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; will know nothing about looging. We can use the same technique to avoid knowing about any similar side-effects which concrete validations might produce.&lt;/p&gt;

&lt;p&gt;First we create an interface, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidator&lt;/code&gt;, that any object that validates clicks should implement:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f99484860f82f9dcb04ee2da38ffc39f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Next we create a new class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt; that wraps the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt; and adapts&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; it to implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidator&lt;/code&gt; interface. This wrapper also enrichs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt;’s’ behavior by taking charge of logging in case the click is not valid.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c4a928f6f7420a339240f0f52fe4f8b1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These are the tests of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt; that takes care of the delegation to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt; and the logging:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/452ce96590c7655f722dd4d42f49ba4c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;If we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;, we’d remove all knowledge about logging from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/cc9b89b5dd5890cfec3d5104f78663fe.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Of course, that knowledge would also disappear from its tests. By using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidator&lt;/code&gt; interface for all concrete validations and wrapping validations with side-effects like logging, we’d make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; tests robust to changes involving some of the possible axis of change that were making them fragile:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Changing the interface of any of the individual validations.&lt;/li&gt;
  &lt;li&gt;Adding side-effects to any of the validations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;2. Another improvement: don&apos;t use test doubles when it&apos;s not worth it&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/h4&gt;

&lt;p&gt;There’s another way to make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; tests less fragile.&lt;/p&gt;

&lt;p&gt;If we have a look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt; (I can’t show their code here for security reasons), they have very different natures. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; has no collaborators, no state and a very simple logic, whereas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt; has several collaborators, state and a complicated validation logic.&lt;/p&gt;

&lt;p&gt;Stubbing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; tests is not giving us any benefit over directly using it, and it’s producing coupling between the tests and the code.&lt;/p&gt;

&lt;p&gt;On the contrary, stubbing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt; (which wraps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BotClickDetector&lt;/code&gt;) is really worth it, because, even though it also produces coupling, it makes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; tests much simpler.&lt;/p&gt;

&lt;p&gt;Using a test double when you’d be better of using the real collaborator is a weakness in the design of the test, rather than in the code to be tested.&lt;/p&gt;

&lt;p&gt;These would be the tests for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; code with no logging knowledge, after applying this idea of not using test doubles for everything:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/bc99d68fc4536dd81b24b75df9d7e8eb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how the tests now use the real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; and how that reduces the coupling with the production code and makes the set up simpler.&lt;/p&gt;

&lt;h4&gt;3. Removing knowledge about the concrete sequence of validations.&lt;/h4&gt;

&lt;p&gt;After this change, the new design will compose validations in a way that will result in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; being only in charge of combining the result of a given sequence of validations.&lt;/p&gt;

&lt;p&gt;First we refactor the click validation so that the validation is now done by composing several validations:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1eadf6e2f681bd48aa50abc1562783ce.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The new validation code has several advantages over the previous one:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It does not depend on concrete validations any more&lt;/li&gt;
  &lt;li&gt;It does not depend on the order in which the validations are made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has only one responsibility: it applies several validations in sequence, if all of them are valid, it will accept the click, but if any given validation fails, it will reject the click and stop applying the rest of the validations. If you think about it, it’s behaving like an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;and&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;We may write these tests for this new version of the click validation:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/140295bdcd101ce92499b216bcd0b43d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These tests are robust to the changes making the initial version of the tests fragile that we described in the introduction:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Changing the interface of any of the individual validations.&lt;/li&gt;
  &lt;li&gt;Adding side-effects to any of the validations.&lt;/li&gt;
  &lt;li&gt;Adding more validations.&lt;/li&gt;
  &lt;li&gt;Changing the order of the validation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, this version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidationTest&lt;/code&gt; is so general and flexible, that using it, our tests would stop knowing which validations, and in which order, are applied to the clicks&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. That sequence of validations is a business rule and, as such, we should protect it. We might keep this version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidationTest&lt;/code&gt; only if we had some outer test protecting the desired sequence of validations.&lt;/p&gt;

&lt;p&gt;This other version of the tests, on the other hand, keeps protecting the business rule:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0ead6e5c1d460ae8494b878422267262.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how this version of the tests keeps in its setup the knowledge of which sequence of validations should be used, and how it only uses test doubles for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;4. Avoid exposing internals.&lt;/h4&gt;

&lt;p&gt;The fact that we’re injecting into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; an object, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt;, that we realized we didn’t need to double, it’s a smell which points to the possibility that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; is an internal detail of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; instead of its peer. So by injecting it, we’re coupling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; users, or at least the code that creates it, to an internal detail of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A better version of this code would hide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickParamsValidator&lt;/code&gt; by instantiating it inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;’s constructor:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e5a538fc19f40e6309ea0d52a91729e3.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;With this change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; recovers the knowledge of the sequence of validations which in the previous section was located in the code that created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are some stereotypes that can help us identify real collaborators (peers)&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;: services that the object needs from its environment so that it can fulfill its responsibilities.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Notifications&lt;/strong&gt;: other parts of the system that need to know when the object changes state or performs an action.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Adjustments or Policies&lt;/strong&gt;: objects that tweak or adapt the object’s behaviour to the needs of the system.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Following these stereotypes, we could argue that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoBotClickValidator&lt;/code&gt; is also an internal detail of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; and shouldn’t be exposed to the tests by injecting it. Hiding it we’d arrive to this other version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/70fca43eac0655974e357ee6daabd445.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;in which we have to inject the real dependencies of the validation, and no internal details are exposed to the client code. This version is very similar to the one we’d have got using tests doubles only for infrastructure.&lt;/p&gt;

&lt;p&gt;The advantage of this version would be that its tests would know the least possible about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;. They’d know only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;’s boundaries marked by the ports injected through its constructor, and ClickValidation`’s public API. That will reduce the coupling between tests and production code, and facilitate refactorings of the validation logic.&lt;/p&gt;

&lt;p&gt;The drawback is that the combinations of test cases in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidationTest&lt;/code&gt; would grow, and may of those test cases would talk about situations happening in the validation boundaries that might be far apart from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;’s callers. This might make the tests hard to understand, specially if some of the validations have a complex logic. When this problem gets severe, we may reduce it by injecting and use test doubles for very complex validators, this is a trade-off in which we decide to accept some coupling with the internal of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; in order to improve the understandability of its tests. In our case, the bot detection was one of those complex components, so we decided to test it separately, and inject it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; so we could double it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt;’s tests, which is why we kept the penultimate version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClickValidation&lt;/code&gt; in which we were injecting the click-not-made-by-a-bot validation.&lt;/p&gt;

&lt;h3&gt;Conclusion. &lt;/h3&gt;

&lt;p&gt;In this post, we tried to play with an example to show how &lt;em&gt;listening to the tests&lt;/em&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt; we can detect possible design problems, and how we can use that feedback to improve both the design of our code and its tests, when changes that expose those design problems are required.&lt;/p&gt;

&lt;p&gt;In this case, the initial tests were fragile because the production code was procedural and had too many responsibilities. The tests were fragile also because they were using test doubles for some collaborators when it wasn’t worth to do it.&lt;/p&gt;

&lt;p&gt;Then we showed how refactoring the original code to be more object-oriented and separating better its responsibilities, could
remove some of the fragility of the tests. We also showed how reducing the use of test doubles only to those collaborators that really needs to be substituted can improve the tests and reduce their fragility. Finally, we showed how we can go too far in trying to make the tests flexible and robust, and accidentally stop protecting a business rule, and how a less flexible version of the tests can fix that.&lt;/p&gt;

&lt;p&gt;When faced with fragility due to coupling between tests and the code being tested caused by using test doubles, it’s easy and very usual to “blame the mocks”, but, we believe, it would be more productive to &lt;em&gt;listen to the tests&lt;/em&gt; to notice which improvements in our design they are suggesting. If we act on this feedback the tests doubles give us about our design, we can use tests doubles in our advantage, as powerful feedback tools&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;,
that help us improve our designs, instead of just suffering and blaming them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many thanks to my &lt;a href=&quot;https://codesai.com/&quot;&gt;Codesai&lt;/a&gt; colleagues &lt;a href=&quot;https://twitter.com/alfredocasado?lang=en&quot;&gt;Alfredo Casado&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mjtordesillas&quot;&gt;Manuel Tordesillas&lt;/a&gt;, and to my &lt;a href=&quot;https://twitter.com/deAprendices&quot;&gt;Aprendices&lt;/a&gt; colleagues &lt;a href=&quot;https://twitter.com/pclavijo&quot;&gt;Paulo Clavijo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alvarobiz?lang=en&quot;&gt;Álvaro García&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mintxelas&quot;&gt;Fermin Saez&lt;/a&gt; for their feedback on the post, and to my colleagues at &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;LIFULL Connect&lt;/a&gt; for all the mobs we enjoy together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See the &lt;a href=&quot;https://en.wikipedia.org/wiki/Adapter_pattern&quot;&gt;Adapter or wrapper pattern&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] See &lt;a href=&quot;https://web.archive.org/web/20210801150000/http://www.mockobjects.com/2007/04/test-smell-everything-is-mocked.html&quot;&gt;Test Smell: Everything is mocked&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman/?originalSubdomain=uk&quot;&gt;Steve Freeman&lt;/a&gt; where he talks about things you shouldn&apos;t be substituting with tests doubles.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Thanks &lt;a href=&quot;https://twitter.com/alfredocasado?lang=en&quot;&gt;Alfredo Casado&lt;/a&gt; for detecting that problem in the first version of the post.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] From &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt; &amp;gt; Chapter 6, Object-Oriented Style &amp;gt; Object Peer Stereotypes, page 52. You can also read about these stereotypes in a post by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman/?originalSubdomain=uk&quot;&gt;Steve Freeman&lt;/a&gt;: &lt;a href=&quot;https://web.archive.org/web/20210801140344/http://www.mockobjects.com/2006/10/different-kinds-of-collaborators.html&quot;&gt;Object Collaboration Stereotypes&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] Difficulties in testing might be a hint of design problems. Have a look at this interesting &lt;a href=&quot;https://web.archive.org/web/20210426022938/http://www.mockobjects.com/search/label/listening%20to%20the%20tests&quot;&gt;series of posts about listening to the tests&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman/?originalSubdomain=uk&quot;&gt;Steve Freeman&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] According to &lt;a href=&quot;http://www.natpryce.com/&quot;&gt;Nat Pryce&lt;/a&gt; mocks were designed as a feedback tool for designing OO code following the &apos;Tell, Don&apos;t Ask&apos; principle: &quot;In my opinion it&apos;s better to focus on the benefits of different design styles in different contexts (there are usually many in the same system) and what that implies for modularisation and inter-module interfaces. Different design styles have different techniques that are
most applicable for test-driving code written in those styles, and there are different tools that help you with those techniques. Those tools should give useful feedback about the external and *internal* quality of the system so that programmers can &apos;listen to the tests&apos;. That&apos;s what we -- with the help of many vocal users over many years -- designed jMock to do for &apos;Tell, Don&apos;t Ask&apos; object-oriented design.&quot; (from &lt;a href=&quot;https://groups.google.com/forum/#!topic/growing-object-oriented-software/dOmOIafFDcI&quot;&gt;a conversation in Growing Object-Oriented Software Google Group&lt;/a&gt;). &lt;br /&gt; &lt;br /&gt;I think that if your design follows a different OO style, it might be preferable to stick to a classical TDD style which nearly limits the use of test doubles only to infrastructure and undesirable side-effects.
&lt;/div&gt;

</description>
          <pubDate>2019-06-29T05:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/06/listening-to-tests-to-go-more-oo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/06/listening-to-tests-to-go-more-oo</guid>
        </item>
      
    
      
        <item>
          <title>The curious case of the negative builder</title>
          <description>&lt;h3&gt;Introduction. &lt;/h3&gt;
&lt;p&gt;Recently, one of the teams I’m coaching at my current client, asked me to help them with a problem, they were experiencing while using TDD to add and validate new mandatory query string parameters&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. This is a shortened version (validating fewer parameters than the original code) of the tests they were having problems with:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e90b5daa64147a740571ba03b3f4c15d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the implementation of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QueryStringBuilder&lt;/code&gt; used in this test:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8c9558ba57e945828ccbfea453ccf81b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which is a builder with a fluid interface that follows to the letter a typical implementation of the pattern. There are even libraries that help you to automatically create this kind of builders&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;The problem. &lt;/h3&gt;
&lt;p&gt;In this particular case, however, implementing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QueryStringBuilder&lt;/code&gt; following this typical recipe causes a lot of problems. Looking at the test code, you may see why.&lt;/p&gt;

&lt;p&gt;To add a new mandatory parameter, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sourceId&lt;/code&gt;, following the TDD cycle, you would first write a new test asserting that a query string lacking the parameter should not be valid.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9d62133a3ea3ba8b4aff07b55afe196d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;So far so good, the problem comes when you change the production code to make this test pass, in that moment you’ll see how the first test that was asserting that a query string with all the parameters was valid starts to fail (if you check the query string of that tests and the one in the new test, you’ll see how they are the same). Not only that, all the previous tests that were asserting that a query string was invalid because a given parameter was lacking won’t be “true” anymore because after this change they could fail for more than one reason.&lt;/p&gt;

&lt;p&gt;So to carry on, you’d need to fix the first test and also change all the previous ones so that they fail again only for the reason described in the test name:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/74bb550cb2dcf0b9b4739c1614aa1f24.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;That’s a lot of rework on the tests only for adding a new parameter, and the team had to add many more. The typical implementation of a builder was not helping them.&lt;/p&gt;

&lt;h3&gt;The &quot;negative builder&quot;. &lt;/h3&gt;

&lt;p&gt;The problem we’ve just explained can be avoided by chosing a default value that creates a valid query string and what I call “a negative builder”, a builder with methods that remove parts instead of adding them. So we refactored together the initial version of the tests and the builder, until we got to this new version of the tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/4d7c8f23059e56082cd54a9bd7240c6c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which used a “negative” &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QueryStringBuilder&lt;/code&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/68967ff6c5cbbd696c8e74a54fdaed6c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After this refactoring, to add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sourceId&lt;/code&gt; we wrote this test instead:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/9d63b864943f6a76299610925833f977.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which only carries with it updating the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valid&lt;/code&gt; method in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QueryStringBuilder&lt;/code&gt; and adding a method that removes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sourceId&lt;/code&gt; parameter from a valid query string.&lt;/p&gt;

&lt;p&gt;Now when we changed the code to make this last test pass, no other test failed or started to have descriptions that were not true anymore.&lt;/p&gt;

&lt;h3&gt;Conclusions.&lt;/h3&gt;

&lt;p&gt;Leaving behind the typical recipe and adapting the idea of the builder pattern to the context of the problem at hand, led us to a curious implementation, a “negative builder”, that made the tests easier to maintain and improved our TDD flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many thanks to my &lt;a href=&quot;https://codesai.com/&quot;&gt;Codesai&lt;/a&gt; colleagues &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt;, and to all the colleagues of the &lt;strong&gt;Prime Services Team&lt;/strong&gt; at &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;LIFULL Connect&lt;/a&gt; for all the mobs we enjoy together. Thanks also to &lt;a href=&quot;https://www.pexels.com/@markusspiske&quot;&gt;Markus Spiske&lt;/a&gt;  for the &lt;a href=&quot;https://www.pexels.com/photo/accurate-boy-build-building-298825/&quot;&gt;photo used in this post&lt;/a&gt; and to &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Currently, this validation is not done in the controller anymore. The code showed above belongs to a very early stage of an API we&apos;re developing.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Have a look, for instance, at &lt;a href=&quot;https://projectlombok.org/&quot;&gt;lombok&lt;/a&gt;&apos;s&apos; &lt;code class=&quot;highlighter-rouge&quot;&gt;@Builder&lt;/code&gt; annotation for Java.
&lt;/div&gt;
</description>
          <pubDate>2019-05-24T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/05/negative-builder</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/05/negative-builder</guid>
        </item>
      
    
      
        <item>
          <title>CAS 2018: Una vida descubriendo Agile</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/post-una-vida-oficial1.jpg&quot; alt=&quot;Toño de la Torre dando la charla con la pantalla de fondo&quot; /&gt;
&lt;em&gt;Todos los derechos reservados por &lt;a href=&quot;https://www.flickr.com/photos/167768694@N04/46356688662/in/album-72157701587805742/&quot;&gt;conferenciaagilespain&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;“Una vida descubriendo Agile” es el título de la charla que di en la pasada &lt;a href=&quot;http://cas2018.agile-spain.org/&quot;&gt;CAS2018 en Alicante&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El vídeo ya está disponible desde hace tiempo (gracias &lt;a href=&quot;https://www.youtube.com/watch?v=W9BX5mYnvj4&amp;amp;list=PLKxa4AIfm4pU2H_iVJOKcjAI1JwMr-ddt&quot;&gt;Autentia!&lt;/a&gt;), y desde que salió, tenía ganas de hacer este post de “cómo se hizo”.&lt;/p&gt;

&lt;h2 id=&quot;cómo-surgió-la-idea&quot;&gt;¿Cómo surgió la idea?&lt;/h2&gt;

&lt;p&gt;Por motivo de &lt;a href=&quot;https://twitter.com/jlvallejo/status/1006553138155999232&quot;&gt;la inauguración de las nuevas oficinas de Sngular en Oviedo&lt;/a&gt; el pasado 21 de junio, tuve el honor de que me propusieran para dar la charla inaugural del evento, como representante de la comunidad y como organizador del grupo &lt;a href=&quot;https://www.meetup.com/es-ES/Agile-Asturias/&quot;&gt;Agile Asturias&lt;/a&gt;.
Sentía la relevancia del momento, así que pensé que una charla muy técnica sobre dinámicas o retrospectivas iba a ser poco inspiradora, tenía que ser algo con un poco más de alma.&lt;/p&gt;

&lt;p&gt;En ese momento se cumplían casi dos años de mi vuelta a Oviedo, en el que al &lt;a href=&quot;https://adelatorrefoss.wordpress.com/2016/07/30/cierre-de-ciclo/&quot;&gt;cierre de un ciclo&lt;/a&gt;, se le unía &lt;a href=&quot;https://adelatorrefoss.wordpress.com/2016/07/30/gracias-madrid/&quot;&gt;dar las gracias a Madrid&lt;/a&gt;, así que necesitaba sentarme a recordar y concretar en algo tangible todas esas experiencias que me marcaron.&lt;/p&gt;

&lt;p&gt;Al empezar a hacerlo observé que había un paralelismo entre mi vida profesional y el descubrimiento del mundo del agilismo, así que busqué momentos concretos de mi vida, que a la vez que interesantes en lo autobiográfico, fueran mostrando principios, valores o prácticas ágiles. Sobre todo detalles en los que se pudiera ver reflejado un oyente en su propia experiencia.&lt;/p&gt;

&lt;h2 id=&quot;primera-iteración&quot;&gt;Primera iteración&lt;/h2&gt;

&lt;p&gt;Me quedé bastante contento de cómo fue la charla en Sngular, tanto por el contenido, como por el ‘delivery’, me sentí muy cómodo en el ambiente que se creó. Si tenéis curiosdad podéis ver el vídeo &lt;a href=&quot;https://www.youtube.com/watch?v=IDQaH2MeHLs&quot;&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pero lo más importante… ¡ya tenía tema para la CAS! Y lo mejor, ¡la presenté y me la aceptaron! \o/&lt;/p&gt;

&lt;p&gt;Y como no es muy habitual tener ya el trabajo hecho, ya que tenía tiempo, pedí feedback a algunos amigos. Entre los que me contestaron estaba &lt;a href=&quot;https://jmbeas.es/&quot;&gt;José Manuel Beas&lt;/a&gt;, para el que &lt;a href=&quot;https://twitter.com/bberrycarmen/status/1119561541702103040&quot;&gt;dar un feedback trabajado es norma&lt;/a&gt;, me comentó que podría darle la estructura del &lt;a href=&quot;https://es.wikipedia.org/wiki/Monomito&quot;&gt;Viaje del Héroe&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;display: table; margin: 0 auto;&quot;&gt;
  &lt;img src=&quot;/assets/post-una-vida-monomito-450.png&quot; alt=&quot;Diagrama del Viaje del Héroe&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Y efectivamente estudiando sobre ella encajaba como un guante. Así que reordené algunos eventos y reforcé algo la épica y el drama de ciertos momentos de la historia para hacerla más atractiva.&lt;/p&gt;

&lt;h2 id=&quot;cas-2018&quot;&gt;CAS 2018&lt;/h2&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Empezamos!! &lt;a href=&quot;https://twitter.com/hashtag/CAS2018?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#CAS2018&lt;/a&gt; &lt;a href=&quot;https://t.co/4XygBVqFt5&quot;&gt;pic.twitter.com/4XygBVqFt5&lt;/a&gt;&lt;/p&gt;&amp;mdash; Toño de la Torre (@adelatorrefoss) &lt;a href=&quot;https://twitter.com/adelatorrefoss/status/1073137848658878464?ref_src=twsrc%5Etfw&quot;&gt;December 13, 2018&lt;/a&gt;&lt;/blockquote&gt; 
  &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt; 
&lt;/section&gt;

&lt;p&gt;Y llegó la CAS. Estaba bastante nervioso, así que no me centré demasiado en ninguna charla durante la jornada. A diferencia de otras ocasiones no buscaba tanto la información precisa, si no el clima adecuado para la historia tan personal que quería contar.&lt;/p&gt;

&lt;p&gt;Empecé mi charla buscando la complicidad del público, invitándoles más a escuchar que a tomar notas, a que me acompañasen en el viaje. Y creo que funcionó, me sentí muy a gusto desde el primer momento.&lt;/p&gt;

&lt;p&gt;Pero no me imaginaba que iba a tener un un ayudante inesperado. ¡El proyector se quemó en mitad de la exposición!&lt;/p&gt;

&lt;p&gt;Mientras intentaba continuar, pidiendo a la gente que se quedase conmigo, veía a los técnicos entrar y salir intentando solucionar el problema.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Olé la capacidad de improvisación de &lt;a href=&quot;https://twitter.com/adelatorrefoss?ref_src=twsrc%5Etfw&quot;&gt;@adelatorrefoss&lt;/a&gt; ante la adversidad técnica 🔝&lt;a href=&quot;https://twitter.com/hashtag/CAS2018?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#CAS2018&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/Keepitreal?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#Keepitreal&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/keepcalm?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#keepcalm&lt;/a&gt; 💆🏻‍♂️ &lt;a href=&quot;https://t.co/YkzTogDMDW&quot;&gt;pic.twitter.com/YkzTogDMDW&lt;/a&gt;&lt;/p&gt;&amp;mdash; Laura Azcona (@lauraazcona) &lt;a href=&quot;https://twitter.com/lauraazcona/status/1073263069541949441?ref_src=twsrc%5Etfw&quot;&gt;December 13, 2018&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt; 
&lt;/section&gt;

&lt;p&gt;Cuando ya vinieron a informar que no había remedio, hubo un fugaz momento que pensé en cancelar. Pero enseguida decidí que había que seguir, porque aunque las imágenes eran interesantes, era mucho más relevante toda la emoción que había volcado en mi pequeña historia y quería tranmitirla.&lt;/p&gt;

&lt;p&gt;Así que solventamos el problema dando la vuelta al portátil y pidiendo a la gente que ocupase las primeras filas de la sala.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/adelatorrefoss?ref_src=twsrc%5Etfw&quot;&gt;@adelatorrefoss&lt;/a&gt; luchando contra el entorno y abriéndose a la audiencia como un campeón. ¡Enhorabuena Toño! &lt;br /&gt;Veníamos sobre todo a escuchar tu experiencia, aunque las fotos fueran chulas. &lt;a href=&quot;https://twitter.com/hashtag/CAS2018?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#CAS2018&lt;/a&gt; &lt;a href=&quot;https://t.co/hMmaJlaPhY&quot;&gt;pic.twitter.com/hMmaJlaPhY&lt;/a&gt;&lt;/p&gt;&amp;mdash; Enrique de la Cruz Martínez (@encrumar) &lt;a href=&quot;https://twitter.com/encrumar/status/1073264449396592640?ref_src=twsrc%5Etfw&quot;&gt;December 13, 2018&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt; 
&lt;/section&gt;

&lt;p&gt;Así terminó la charla, como dice Enrique en este tweet, desnudándome (un poco) ante los asistentes y con una sensación muy agradable de haber compartido mi camino en un ambiente de confianza.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Gracias por el feedback! &lt;a href=&quot;https://twitter.com/hashtag/CAS2018?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#CAS2018&lt;/a&gt; &lt;a href=&quot;https://t.co/lxNd9MCu7K&quot;&gt;pic.twitter.com/lxNd9MCu7K&lt;/a&gt;&lt;/p&gt;&amp;mdash; Toño de la Torre (@adelatorrefoss) &lt;a href=&quot;https://twitter.com/adelatorrefoss/status/1073289226127622146?ref_src=twsrc%5Etfw&quot;&gt;December 13, 2018&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt; 
&lt;/section&gt;

&lt;p&gt;El feedback fue muy bueno, tanto el que dejaron en la urna, como el que me fueron dando el resto del día y todo el día siguiente: Bastantes personas se acercaron a felicitarme por la charla y por superar con aparente naturalidad el problema del proyector; y lo más valioso para mi, compartir que se vieron identificadas en algunas partes del relato.&lt;/p&gt;

&lt;p&gt;Así que quedé muy satisfecho con el trabajo de recordar 14 años de mi vida, con transparencia y honestidad de los momentos buenos y no tan buenos, en el que he podido volver a agradecer a varias personas allí presentes lo importantes que fueron en mi vida.&lt;/p&gt;

&lt;p&gt;¡Gracias!&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;y9FLkaN7Yxo&quot;&gt;
    &lt;div data-id=&quot;y9FLkaN7Yxo&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/y9FLkaN7Yxo/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;h3 id=&quot;referencias&quot;&gt;Referencias&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/167768694@N04/albums/72157701587805742/page6&quot;&gt;Fotos oficiales de la CAS2018&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Más sobre el Monomito o El viaje del héroe contado por Juan Gómez-Jurado: &lt;a href=&quot;http://todopoderosos.net/todopoderosos-15-star-wars-y-los-chorizos-parrilleros-star-wars-vol-i&quot;&gt;TODOPODEROSOS #15: Star Wars y los chorizos parrilleros (Star Wars, Vol I)&lt;/a&gt;&lt;/p&gt;

&lt;div style=&quot;display: table; margin: 0 auto;&quot;&gt;
  &lt;img src=&quot;/assets/post-una-vida-oficial3.jpg&quot; alt=&quot;Primer plano de Toño de la Torre dando la charla&quot; /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Todos los derechos reservados por &lt;a href=&quot;https://www.flickr.com/photos/167768694@N04/46356687692/in/album-72157701587805742/&quot;&gt;conferenciaagilespain&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
          <pubDate>2019-05-23T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/05/cas-2018-una-vida-aprendiendo-agile</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/05/cas-2018-una-vida-aprendiendo-agile</guid>
        </item>
      
    
      
        <item>
          <title>Killing mutants to improve your tests</title>
          <description>&lt;p&gt;At my current client we’re working on having a frontend architecture for writing SPAs in JavaScript similar to &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;’s one: an event-driven bus with effects and coeffects for state management&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; (commands) and subscriptions using &lt;a href=&quot;https://github.com/reduxjs/reselect&quot;&gt;reselect&lt;/a&gt;’s selectors (queries).&lt;/p&gt;

&lt;p&gt;One of the pieces we have developed to achieved that goal is &lt;a href=&quot;https://github.com/trovit/reffects/tree/master/packages/reffects-store&quot;&gt;reffects-store&lt;/a&gt;. Using this store, &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt; components can be subscribed to given &lt;a href=&quot;https://github.com/reduxjs/reselect&quot;&gt;reselect&lt;/a&gt;’s selectors, so that they only render when the values in the application state tracked by the selectors change.&lt;/p&gt;

&lt;p&gt;After we finished writing the code for the store, we decided to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;mutation testing&lt;/a&gt; to evaluate the quality of our tests. &lt;em&gt;Mutation testing&lt;/em&gt; is a technique in which, you introduce bugs, (&lt;em&gt;mutations&lt;/em&gt;), into your production code, and then run your tests for each mutation. If your tests fail, it’s ok, the mutation was “killed”, that means that they were able to defend you against the regression caused by the mutation. If they don’t, it means your tests are not defending you against that regression. The higher the percentage of mutations killed, the more effective your tests are.&lt;/p&gt;

&lt;p&gt;There are tools that do this automatically, &lt;a href=&quot;https://stryker-mutator.io/&quot;&gt;stryker&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; is one of them. When you run &lt;em&gt;stryker&lt;/em&gt;, it will create many mutant versions of your production code, and run your tests for each mutant (that’s how mutations are called in &lt;em&gt;stryker&lt;/em&gt;’s’ documentation) version of the code. If your tests fail then the mutant is killed. If your tests passed, the mutant survived. Let’s have a look at the the result of runnning &lt;em&gt;stryker&lt;/em&gt; against &lt;a href=&quot;ttps://github.com/trovit/reffects/tree/master/packages/reffects-store&quot;&gt;reffects-store&lt;/a&gt;’s code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0fe2dee6b69016d784849f61d3cae80f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how &lt;em&gt;stryker&lt;/em&gt; shows the details of every mutation that survived our tests, and look at the summary the it produces at the end of the process.&lt;/p&gt;

&lt;p&gt;All the surviving mutants were produced by mutations to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store.js&lt;/code&gt; file. Having a closer look to the mutations in &lt;em&gt;stryker&lt;/em&gt;’s output we found that the functions with mutant code were &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeAllListeners&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeListener&lt;/code&gt;.
After a quick check of their tests, it was esay to find out why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeAllListeners&lt;/code&gt; was having surviving mutants. Since it was a function we used only in tests for cleaning the state after each test case was run, we had forgotten to test it.&lt;/p&gt;

&lt;p&gt;However, finding out why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeListener&lt;/code&gt; mutants were surviving took us a bit more time and thinking.
Let’s have a look at the tests that were exercising the code used to subscribe and unsubscribe listeners of state changes:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/62a6892d957ffc21d9f9430fd4b2f359.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;If we examine the mutations and the tests, we can see that the tests for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeListener&lt;/code&gt; are not good enough. They are throwing an exception from the subscribed function we unsubscribe, so that if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeListener&lt;/code&gt; function doesn’t work and that function is called the test fails. Unfortunately, the test passes also if that function is never called for any reason. In fact, most of the surviving mutants that &lt;em&gt;stryker&lt;/em&gt; found above have are variations on that idea.&lt;/p&gt;

&lt;p&gt;A better way to test &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeListener&lt;/code&gt; is using spies to verify that subscribed functions are called and unsubscribed functions are not (this version of the tests includes also a test for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribeAllListeners&lt;/code&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/4e64ce106b74e0f3b9e304933a32fc35.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After this change, when we run &lt;em&gt;stryker&lt;/em&gt; we got the following output:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/93b40e7f4318159f2c3022b8e0119811.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;No mutants survived!! This means this new version of the tests is more reliable and will protect us better from regressions than the initial version.&lt;/p&gt;

&lt;p&gt;Mutation testing is a great tool to know if you can trust your tests. This is event more true when working with legacy code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a href=&quot;https://twitter.com/MrMSanchez&quot;&gt;Mario Sánchez&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/alexhoma_&quot;&gt;Alex Casajuana Martín&lt;/a&gt; for all the great time coding together, and thanks to Porapak Apichodilok for the &lt;a href=&quot;https://www.pexels.com/photo/boy-child-clouds-kid-346796/&quot;&gt;photo used in this post&lt;/a&gt; and to &lt;a href=&quot;https://www.pexels.com/&quot;&gt;Pexels&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See also &lt;a href=&quot;https://github.com/trovit/reffects&quot;&gt;reffects&lt;/a&gt; which is the synchronous event bus with effects and coeffects we wrote to manage the application state.
&lt;/div&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] The name of this tool comes from a fictional Marvel comics supervillain &lt;a href=&quot;https://en.wikipedia.org/wiki/William_Stryker&quot;&gt;Willian Stryker&lt;/a&gt; who was obsessed with the eradication of all mutants.
&lt;/div&gt;
</description>
          <pubDate>2019-05-14T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/05/killing-mutants-to-improve-tests</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/05/killing-mutants-to-improve-tests</guid>
        </item>
      
    
      
        <item>
          <title>The Beverages Prices Refactoring kata: a kata to practice refactoring away from an awful application of inheritance.</title>
          <description>&lt;p&gt;I created the &lt;a href=&quot;https://github.com/trikitrok/beverages_pricing_refactoring_kata&quot;&gt;Beverages Prices Refactoring kata&lt;/a&gt; for the &lt;a href=&quot;https://github.com/Codesai/practice_program&quot;&gt;Deliberate Practice Program&lt;/a&gt; I’m running at &lt;a href=&quot;https://www.lifullconnect.com/&quot;&gt;Lifull Connect&lt;/a&gt; offices in Barcelona (previously &lt;a href=&quot;https://www.trovit.es/index.php&quot;&gt;Trovit&lt;/a&gt;). Its goal is to practice refactoring away from a bad usage of inheritance.&lt;/p&gt;

&lt;p&gt;The code computes the price of the different beverages that are sold in a coffee house. There are some supplements that can be added to those beverages. Each supplement increases the price a bit. Not all combinations of drinks and supplements are possible.&lt;/p&gt;

&lt;p&gt;Just having a quick look at the tests of the initial code would give you an idea of the kind of problems it might have:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a9b2b77762045a77cfd9c6854046add7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;If that’s not enough have a look at its inheritance hierarchy:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/beverages_prices_inheritance_hierarchy.png&quot; alt=&quot;Inheritance hierarchy in the initial code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To make things worse, we are asked to &lt;strong&gt;add an optional cinnamon supplement that costs 0.05€
to all our existing catalog of beverages&lt;/strong&gt;. We think we should refactor this code a bit before introducing the new feature.&lt;/p&gt;

&lt;p&gt;We hope you have fun practicing refactoring with this kata.&lt;/p&gt;
</description>
          <pubDate>2019-04-07T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/04/beverages_prices_kata</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/04/beverages_prices_kata</guid>
        </item>
      
    
      
        <item>
          <title>Our experience at ClojureBridge Bilbao 2018</title>
          <description>&lt;p&gt;&lt;a href=&quot;https://clojurebridge.org/about/&quot;&gt;ClojureBridge&lt;/a&gt; is an all-volunteer organization inspired by &lt;a href=&quot;http://www.railsbridge.org/&quot;&gt;RailsBridge&lt;/a&gt; that provides free, introductory workshops to increase diversity in the Clojure community. I first learned about ClojureBridge thanks to a talk by &lt;a href=&quot;https://twitter.com/ali_king&quot;&gt;Ali King&lt;/a&gt; at EuroClojure 2015 in Barcelona: &lt;a href=&quot;https://www.youtube.com/watch?v=ici57gdUzqo&quot;&gt;ClojureBridge, Building a more diverse Clojure community&lt;/a&gt;. I really liked the idea and we (the &lt;a href=&quot;https://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Developers Barcelona&lt;/a&gt;) tried to organize one in Barcelona, but failed to actually do it because we lacked the numbers, money and time. So the moment I knew that my colleague at &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@estibaliz.rodriguez&quot;&gt;Estíbaliz Rodríguez&lt;/a&gt;, and the company where she works, &lt;a href=&quot;https://www.magnet.coop/&quot;&gt;Magnet&lt;/a&gt;, were planning to organize &lt;a href=&quot;https://clojurebridge.org/events/2018-12-01-bilbao&quot;&gt;a ClojureBridge edition in Bilbao&lt;/a&gt; for December 1st 2018, I decided to do my best to help.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/clojure_bridge_2018_intro.jpg&quot; alt=&quot;ClojureBridge 2018 Bilbao introduction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I met Estíbaliz and &lt;a href=&quot;https://www.linkedin.com/in/joseayudarte/&quot;&gt;José Ayudarte&lt;/a&gt; at the beginning of last summer, when they started working as ClojureScript developers for &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt;, and it’s been a great experience to work with them. They are part of &lt;a href=&quot;https://www.magnet.coop/&quot;&gt;Magnet&lt;/a&gt; which is a cooperative of developers, designers and consultants that work with Clojure and ClojureScript. &lt;a href=&quot;https://www.magnet.coop/team&quot;&gt;Magnet’s team&lt;/a&gt; is distributed across Europe but most of them live in the Basque country.&lt;/p&gt;

&lt;p&gt;I told them I’d like to participate as a volunteer. Actually I had already bought the tickets and booked an accommodation for that weekend before asking them. In the worst-case scenario, if I couldn’t participate in ClojureBridge, I’d at least spend a weekend in Bilbao which is a wonderful city. In the end, everything went well and they told me they were delighted to have me there. I participated in a couple of meetings to know the other volunteers and talk about how the event would be structured, the mentoring and the exercises. Magnet was sponsoring the event and most of its team worked very hard to make it possible.&lt;/p&gt;

&lt;p&gt;So, on December 1st I was there trying to help people learn a bit of Clojure. There were many women and girls with very diverse backgrounds: professional developers that were using other languages, teenagers with a bit of programming experience from school or without, little girls and women of all ages that had no programming experience. At the beginning, Usoa Sasigain gave a talk to introduce the clojureBridge aim of increasing diversity in technology, the important role women have played in the history of computer science and technology, and Clojure. She also talked about her personal history with technology and Clojure, and explained how technology might be a nice career option for women.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/clojure_bridge_2018_grace.jpg&quot; alt=&quot;ClojureBridge 2018 Bilbao Grace Hopper slide&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After the introduction, the participants were splitted in groups according to their programming experience. I was assigned to help the group of experienced software developers. They worked through the exercises in &lt;a href=&quot;https://www.maria.cloud/&quot;&gt;Maria Cloud&lt;/a&gt; which is &lt;a href=&quot;https://www.youtube.com/watch?v=CUBHrS4ZzO4&quot;&gt;a beginner-friendly coding environment for Clojure&lt;/a&gt; and I answered to questions about Clojure and helped when they got stuck. I think they got to appreciate Clojure and the possibilities it offers. We did several coffee breaks during the morning and for lunch in which we could talk about many things and I had the opportunity to meet &lt;a href=&quot;https://medium.com/@agaldos&quot;&gt;Asier Galdós&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/amaia-guridi-3bb23653/&quot;&gt;Amaia Guridi&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@iperdomo&quot;&gt;Iván Perdomo&lt;/a&gt; and other members of Magnet. The lunch was very nice and sponsored by Magnet.&lt;/p&gt;

&lt;p&gt;At the end of the first half of the event, some attendees had to go to have lunch with their families. A funny and lovely anecdote for me happened when two girls of about six or eight years old that had been enthusiastically programming all the morning didn’t want to stop and leave with their parents for lunch. I remember with a lot of tenderness seeing them totally engrossed in programming during the morning and celebrating with raised arms every time they succeeded in changing the color or any other feature of the shapes they were working with in Maria Cloud’s exercises.&lt;/p&gt;

&lt;p&gt;During the afternoon, we continue working on more advanced Maria Cloud exercises. There were less people, so I changed to work with some women that had no previous experience with programming. It was a very nice experience and we had a good time going through some more Maria cloud’s exercises playing with shapes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/clojure_bridge_2018_mccarthy.jpg&quot; alt=&quot;ClojureBridge 2018 Bilbao John McCarthy slide&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All in all, volunteering in ClojureBridge was a very beautiful experience for me. I enjoyed helping people to know Clojure and programming, and met many nice people with many different backgrounds. I learned several words in basque language. I also had some very interesting conversations with Asier, Usoa, José and Iván about Clojure, Magnet’s experience as a Clojure/ClojureScript cooperative and the interesting platform, &lt;a href=&quot;https://www.magnet.coop/why-hydrogen-platform&quot;&gt;Hydrogen&lt;/a&gt;, that they are building. We also talked about my doing a desk surfing with them, an idea that I was really excited about, but, unfortunately, I haven’t been able to do yet because I recently started working for a new client in Barcelona.&lt;/p&gt;

&lt;p&gt;Before finishing I’d like to thank Magnet for making the first ClojureBridge in Spain possible and for letting me help. I’d also like to send love and good energy to Estíbaliz. I hope you recover soon and we can meet each other in Euskadi or somewhere else.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/clojure_bridge_group.jpeg&quot; alt=&quot;Asistentes y voluntarios ClojureBridge 2018 Bilbao&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2019-03-23T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/03/clojurebridge-bilbao-2018</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/03/clojurebridge-bilbao-2018</guid>
        </item>
      
    
      
        <item>
          <title>Charla Pyday Tenerife</title>
          <description>&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-sm-8&quot;&gt;
    &lt;img src=&quot;/assets/pydayfran.jpg&quot; alt=&quot;fran en el pyday tf&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El pasado 17 de Noviembre tuvo lugar el &lt;a href=&quot;https://pythoncanarias.es/events/pydaytf18/&quot;&gt;PyDay Tenerife&lt;/a&gt;, un evento que reune a muchos amantes de este lenguaje. Pero no sólo se habla del lenguaje. El evento deja bastante espacio para otras cosas relacionadas con el lenguaje, lo que hace que la diversidad de temas sea amplia y eso se nota también en el público que asiste.&lt;/p&gt;

&lt;p&gt;Con este panorama me animé a presentar una charla sobre TDD relacionada con mi reciente experiencia usando el lenguaje a pesar de no tener una gran experiencia con el mismo. Mi intención era aportar mi granito de arena a otras comunidades locales de las que habitualmente participo.&lt;/p&gt;

&lt;p&gt;Aunque en la charla hay una introducción a TDD, la idea principal es hablar sobre la importancia de escuchar a los tests ( algo de lo que ya hablamos en este &lt;a href=&quot;/2018/06/improving-your-reds&quot;&gt;post&lt;/a&gt; ). Otro aspecto destacable son las pequeñas variaciones en el ciclo que son propuestos en el &lt;a href=&quot;http://www.growing-object-oriented-software.com/index.html&quot;&gt;GOOS&lt;/a&gt; y que vertebran la charla.&lt;/p&gt;

&lt;p&gt;A continuación les dejo la grabación de la charla.&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;e-d1P-kZIfs&quot;&gt;
    &lt;div data-id=&quot;e-d1P-kZIfs&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/e-d1P-kZIfs/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Nota: Hay un pequeño problema de sincronización de imagen así que dejo las &lt;a href=&quot;http://buildingthepath.com/talk-pydaytf-2018/&quot;&gt;slides&lt;/a&gt; con la intención de ayudar a mejorar la experiencia.&lt;/p&gt;

&lt;p&gt;Muchísimas gracias a la organización por hacer tan fácil la participación y crear un ambiente muy confortable. Espero participar en la siguiente edición.&lt;/p&gt;

</description>
          <pubDate>2019-01-31T01:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/01/pyday-tf</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/01/pyday-tf</guid>
        </item>
      
    
      
        <item>
          <title>Avoid using subscriptions only as app-state getters</title>
          <description>&lt;h3&gt;Introduction. &lt;/h3&gt;
&lt;p&gt;Subscriptions in &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt; or &lt;a href=&quot;/2018/10/re-om&quot;&gt;re-om&lt;/a&gt; are query functions that extract data from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt; and provide it to view functions in the right format. When we use subscriptions well, they provide a lot of value&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;, because they &lt;em&gt;avoid having to keep derived state the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt;&lt;/em&gt; and they &lt;em&gt;dumb down the views&lt;/em&gt;, that end up being simple “data in, screen out” functions.&lt;/p&gt;

&lt;p&gt;However, things are not that easy. When you start working with subscriptions, it might happen that you end up using them as mere &lt;em&gt;getters&lt;/em&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt;. This is a missed opportunity because using subscriptions in this way, we won’t take advantage of all the value they can provide, and we run the risk of leaking pieces of untested logic into our views.&lt;/p&gt;

&lt;h3&gt;An example. &lt;/h3&gt;
&lt;p&gt;We’ll illustrate this problem with a small real example written with re-om subscriptions (in an app using re-frame subscriptions the problem would look similar). Have a look at this piece of view code in which some details have been elided for brevity sake:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/201a88170cd2807d71ed339473fc48ab.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;this code is using subscriptions written in &lt;a href=&quot;https://gist.github.com/trikitrok/ee79f94e3e4062266f7fe0a639a73e36&quot;&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;horizon.domain.reports.dialogs.edit&lt;/code&gt; namespace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The misuse of subscriptions we’d like to show appears on the following piece of the view:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ee70228ba5eaf3ad70113946b6880346.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how the only thing that we need to render this piece of view is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-generation&lt;/code&gt;. To compute its value the code is using several subscriptions to get some values from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt; and binding them to local vars (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-unit&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start-at&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-number&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date-modes&lt;/code&gt;). Those values are then fed to a couple of private functions also defined in the view (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get-next-generation&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-&amp;gt;interval&lt;/code&gt;) to obtain the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-generation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a bad use of subscriptions. Remember subscriptions are &lt;em&gt;query functions&lt;/em&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt; that, used well, &lt;em&gt;help to make views as dumb (with no logic) as possible&lt;/em&gt;. If you &lt;em&gt;push as much logic as possible into subscriptions&lt;/em&gt;, you might achieve views that are so dumb you nearly don’t need to test, and decide to limit your unit tests to do only &lt;a href=&quot;https://martinfowler.com/bliki/SubcutaneousTest.html&quot;&gt;subcutaneous testing&lt;/a&gt; of your SPA.&lt;/p&gt;

&lt;h3&gt;Refactoring: placing the logic in the right place. &lt;/h3&gt;

&lt;p&gt;We can refactor the code shown above to remove all the leaked logic from the view by writing only one subscription called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-generation&lt;/code&gt; which will produce the only information that the view needs. As a result both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get-next-generation&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-&amp;gt;interval&lt;/code&gt; functions will get pushed into the logic behind the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-generation&lt;/code&gt; subscription and dissappear from the view.&lt;/p&gt;

&lt;p&gt;This is the resulting view code after this refactoring:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/14ba88c994be3187ccbca170fca86d91.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this is the resulting pure logic of the new subscription. Notice that, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get-next-generation&lt;/code&gt; function wasn’t pure, we had to change it a bit to make it pure:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/730c5aaade747504c08152c26c9f7836.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After this refactoring the view is much dumber. The previously leaked (an untested) logic in the view (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get-next-generation&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-&amp;gt;interval&lt;/code&gt; functions) has been removed from it. Now that logic can be easyly tested through the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-generation&lt;/code&gt; subscription. This design is also much better than the previous one because it &lt;em&gt;hides how we obtain the data that the view needs&lt;/em&gt;: now both the view and the tests ignore, and so are not coupled, to how the data the view needs is obtained. We might refactor both the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app-state&lt;/code&gt; and the logic now in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get-next-generation&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay-&amp;gt;interval&lt;/code&gt; functions without affecting the view. This is another example of how &lt;em&gt;what is more stable than how&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;The idea to remember is that &lt;strong&gt;subscriptions by themselves don’t make code more testable and maintainable&lt;/strong&gt;. &lt;strong&gt;It’s the way we use subscriptions that produces better code&lt;/strong&gt;. For that &lt;strong&gt;the logic must be in the right place&lt;/strong&gt; which is &lt;strong&gt;not inside the view but behind the subscriptions that provide the data that the view needs&lt;/strong&gt;. If we keep writing “getter” subscriptions” and placing logic in views, we won’t gain all the advantages the subscriptions concept provides and we’ll write poorly designed views coupled to leaked bunches of (very likely untested) logic.&lt;/p&gt;

&lt;h3&gt;Acknowledgements.&lt;/h3&gt;
&lt;p&gt;Many thanks to &lt;a href=&quot;https://github.com/andrestylianos&quot;&gt;André Stylianos Ramos&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; for giving us great feedback to improve this post and for all the interesting conversations.&lt;/p&gt;

&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Subscriptions also make it easier to share code between different views and, in the case of re-frame (and soon re-om as well), they are optimized to minimize unnecessary rerenderings of the views and de-duplicate computations.
&lt;/div&gt;
</description>
          <pubDate>2019-01-03T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2019/01/avoid-subs-as-getters</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2019/01/avoid-subs-as-getters</guid>
        </item>
      
    
      
        <item>
          <title>Eventos como la Software Crafters Barcelona 2018</title>
          <description>&lt;p&gt;El sábado 15 de Septiembre por la noche aterrizaba en Madrid después de haber pasado más de un año viviendo fuera, muy lejos allá en tierras niponas. Y no era sino dos semanas más tarde que iba a asistir a la Software Crafters Barcelona, pues había conseguido pillarme de antemano (y con suerte :) una entrada.&lt;br /&gt;
Había sido un año complicado profesionalmente hablando, con no mucho tiempo libre y un proyecto complejo durante el cual conseguimos superar, no sin dificultad, algunas situaciones delicadas, todo ello mientras estaba 100% remoto en una zona horaria diferente trabajando de noche con el horario al revés. Me hallaba en una etapa en la que no me apetecía apenas dedicarle tiempo al desarrollo fuera del horario de trabajo, y quería darle la vuelta a la tortilla una vez pusiese pie en España de nuevo. Qué mejor manera que asistir a uno de los mayores eventos de Software Crafters?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/scbcn18_three.jpg&quot; alt=&quot;Antonio, Manu y Dani en la SCBCN 18&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;photo-footer&quot;&gt;Este año hemos vuelto a asistir a la Software Crafters Barcelona, en la cual participamos Antonio, Manuel y yo (Dani).&lt;/div&gt;

&lt;p&gt;Cuando me planteé por primera vez ir a una conferencia lo que me venía a la mente era una serie de charlas interesantes, impartidas por personas muy cualificadas, y una oportunidad de conocerlas e intercambiar un par de preguntas. Con esa idea asistí a la CAS 2015 y me encontré con lo que esperaba y algo más. Ese algo más se fue potenciando según asistía a diversos eventos por España llegando hasta la SCBCN 18, y ha pasado a ser el otro gran pro de los eventos.&lt;/p&gt;

&lt;p&gt;El valor que no logré visualizar en mi inicio no es sino el más importante: las personas que conforman la comunidad. Haciendo reflexión, creo que es un poco difícil de imaginar hasta que se experimenta.&lt;br /&gt;
Es la primera vez, y de no conocer a prácticamente nadie según pones un pie en el recinto, sales al cabo de un par de días habiendo intercambiado opiniones y experiencias con todo un abanico de personas. En este punto quisiera enfatizar el valor de dar un paso adelante y hablar con quien no conoces, pero no importa si al inicio los nervios te pueden. Si sigues participando, aunque sea poco a poco irás sintiéndote cada vez más miembro de esta comunidad, y luego resulta que un buen día te das un salto por otra ciudad y quedas para participar en un evento de la comunidad local, o te ves para tomar unas cervezas y ponerte al día. En ocasiones tienes la suerte de conocer a personas muy afines y en un sólo evento ya habréis logrado forjar una buena amistad.&lt;/p&gt;

&lt;p&gt;La Software Crafters Barcelona no decepciona. Gracias a la organización por un evento muy sólido, sobretodo teniendo en cuenta la cantidad de personas, tracks y charlas, que no es nada fácil! Por darnos la oportunidad a todos los asistentes de impregnarnos de conocimiento a la par que nos reunimos con personas de ideas tan similares como diferentes a las propias.
Este año me vi asistiendo a charlas como:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The Science of Not Estimating de &lt;a href=&quot;https://twitter.com/@anemarifiser&quot;&gt;Anemari Fiser&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/@jsrois&quot;&gt;Javier Sánchez&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Dame tus tipos Pegaso de &lt;a href=&quot;https://twitter.com/flipper83&quot;&gt;Jorge Barroso&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Calisthenics, Smells, SOLID, Cohesion and Coupling Connecting the dots de &lt;a href=&quot;https://twitter.com/@pedromsantos&quot;&gt;Pedro Santos&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y además en el Open Space a:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;React Architecture con &lt;a href=&quot;https://twitter.com/gorkma&quot;&gt;Gorka&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/mikelros_&quot;&gt;Mikel&lt;/a&gt; de 540.&lt;/li&gt;
  &lt;li&gt;Object-Oriented Design Workshop de nuevo con &lt;a href=&quot;https://twitter.com/@pedromsantos&quot;&gt;Pedro Santos&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Y también participé junto con Antonio en la sesión de Let’s talk about Cooperativism propuesta por &lt;a href=&quot;https://twitter.com/anxodio&quot;&gt;Ángel&lt;/a&gt; en la que quisieron contar con nuestro punto de vista con respecto a las ideas que hay detrás de haber montado una Cooperativa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/scbcn18_all.jpg&quot; alt=&quot;Foto de todos los asistentes a la SCBCN 18 tomada por Autentia&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;photo-footer&quot;&gt;Gracias a Autentia por la foto de todos los que participamos en el evento!&lt;/div&gt;

&lt;p&gt;Pero he de decir que también me salté otras tantas charlas por quedarme a hablar con una persona u otra. Las charlas pueden aportar una gran motivación a nivel técnico, pero considero que también hace falta un buen grado de motivación personal y que sin ello es difícil ponerse en marcha. Ahí es donde la comunidad que organiza y asiste a un evento se hace notar y es lo que me lleva al punto que intento expresar.&lt;br /&gt;
Desde un debate técnico, a un intercambio de opiniones sobre cualquier tema y el cómo te va la vida, o en mi caso en esta ocasión ¿qué ha sido de ti en Japón? Son el inamovible complemento que considero distingue a un evento, por contar con personas con objetivos parecidos y mentalidades similares a las propias, que te permiten resurgir con mucha más energía una vez finalizado que cuando cruzaste la entrada el primer día.&lt;/p&gt;

&lt;p&gt;Doy fe de que tenemos una comunidad genial en España!&lt;br /&gt;
Muchas gracias!&lt;/p&gt;
</description>
          <pubDate>2018-11-05T20:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/11/eventos-como-la-scbcn-18</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/11/eventos-como-la-scbcn-18</guid>
        </item>
      
    
      
        <item>
          <title>Giving new life to existing Om legacy SPAs with re-om</title>
          <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction.&lt;/h2&gt;

&lt;p&gt;We’re pleased to announce that our client &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt; has allowed us to open-source &lt;a href=&quot;https://github.com/GreenPowerMonitor/re-om&quot;&gt;re-om&lt;/a&gt;, an event-driven functional framework which is giving new life to an existing legacy SPA that uses &lt;a href=&quot;https://github.com/omcljs/om&quot;&gt;Om&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;why-re-om&quot;&gt;Why re-om?&lt;/h2&gt;

&lt;h3 id=&quot;1-the-problem-with-our-spa-imperative-programming-everywhere&quot;&gt;1. The problem with our SPA: imperative programming everywhere.&lt;/h3&gt;

&lt;p&gt;We are working on a legacy ClojureScript SPA, called horizon, that uses Om.&lt;/p&gt;

&lt;p&gt;This SPA might have had some kind of architecture in some moment in the past but technical debt, lack of documentation and design flaws had blurred it. &lt;strong&gt;Business logic&lt;/strong&gt; (in this case, pure logic that decides how to interact with the user or data transformations) and &lt;strong&gt;effectful code&lt;/strong&gt; were not clearly separated.&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;lack of separation of concerns&lt;/strong&gt; was making the SPA hard to evolve because its code was &lt;strong&gt;difficult to understand and to test&lt;/strong&gt;. This resulted in a very low test coverage that amplified even more the problems to evolve the code safely and at a sustainable pace. This was generating &lt;strong&gt;a vicious circle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even more, &lt;strong&gt;conflating pure and effectful code destroys the advantages of functional programming&lt;/strong&gt;. It doesn’t matter that we’re using a language like Clojure, &lt;strong&gt;without clear isolation between pure and effectful code, you’ll end up doing &lt;a href=&quot;https://en.wikipedia.org/wiki/Imperative_programming&quot;&gt;imperative programming&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-a-possible-solution-effects-and-coeffects&quot;&gt;2. A possible solution: effects and coeffects.&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;effects and coeffects&lt;/strong&gt; is a way of getting the &lt;strong&gt;separation of concerns&lt;/strong&gt; we were lacking. They help achieve &lt;strong&gt;a clear isolation of effectful code and business logic&lt;/strong&gt; that &lt;strong&gt;makes the interesting logic pure&lt;/strong&gt; and, as such, &lt;strong&gt;really easy to test and reason about&lt;/strong&gt;. With them we can really enjoy the advantages of functional programming.&lt;/p&gt;

&lt;p&gt;Any piece of logic using a design based on effects and coeffects is comprised of three parts:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Extracting all the needed data from “the world” (using coeffects for getting application state, getting component state, getting DOM state, etc).&lt;/li&gt;
  &lt;li&gt;Using pure functions to compute the description of the side effects to be performed (returning effects for updating application state, sending messages, etc) given what was extracted from “the world” in the previous step (the coeffects).&lt;/li&gt;
  &lt;li&gt;Performing the side effects described by the effects returned by the pure functions executed in the previous step.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the beginning, when re-om wasn’t yet accepted by everyone in the team, we used coeffects and effects which were being manually created  to improve some parts of the SPA, (have a look at &lt;a href=&quot;https://www.codesai.com/2018/07/improving-legacy-om-code-1&quot;&gt;Improving legacy Om code (I)&lt;/a&gt; and &lt;a href=&quot;https://www.codesai.com/2018/07/improving-legacy-om-code-2&quot;&gt;Improving legacy Om code (II)&lt;/a&gt;), but this can get cumbersome quickly.&lt;/p&gt;

&lt;h3 id=&quot;3-an-event-driven-framework-with-effects-and-coeffects-re-frame&quot;&gt;3. An event-driven framework with effects and coeffects: re-frame.&lt;/h3&gt;

&lt;p&gt;Some of us had worked with effects and coeffects before while developing SPAs with &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt; and had experienced how good it is. After working with re-frame, when you come to horizon, you realize how a good architecture can make a dramatic difference in clarity, testability, understandability and easiness of change.&lt;/p&gt;

&lt;p&gt;Having a framework like re-frame removes most of the boilerplate of working with effects and coeffects, creating clear boundaries and constraints that separate pure code from effectful code and gives you a very clear flow to add new functionality that’s very easy to test and protect from regressions. In that sense re-frame’s architecture can be considered what &lt;a href=&quot;https://blog.codinghorror.com/&quot;&gt;Jeff Atwood&lt;/a&gt; defined as &lt;a href=&quot;https://blog.codinghorror.com/falling-into-the-pit-of-success/&quot;&gt;&lt;strong&gt;a pit of success&lt;/strong&gt;&lt;/a&gt; because it is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“a design that makes it easy to do the right things and annoying (but not impossible) to do the wrong&lt;/strong&gt;
&lt;strong&gt;things.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;4-why-not-use-re-frame-then&quot;&gt;4. Why not use re-frame then?&lt;/h3&gt;

&lt;p&gt;In principle using re-frame in our SPA would have been wonderful, but in practice this was never really an option.&lt;/p&gt;

&lt;p&gt;A very important premise for us was that &lt;strong&gt;a rewrite was out of the question because we would have been blocked from producing any new feature for too long. We needed to continue developing new features&lt;/strong&gt;. So we decided we would follow the &lt;a href=&quot;https://www.martinfowler.com/bliki/StranglerApplication.html&quot;&gt;strangler application pattern&lt;/a&gt;, an approach which would allow us to progressively evolve our SPA to use an architecture like re-frame’s one, while being able to keep adding new features all the time. The idea is that all new code would use the new architecture, if it were pragmatically possible, and that we would only change bit by bit those legacy parts that needed to change. This means that during a, probably long, period of time inside the SPA, the new architecture would have to coexist with the old imperative way of coding.&lt;/p&gt;

&lt;p&gt;Even though, following the &lt;strong&gt;strangler application pattern&lt;/strong&gt; was not incompatible with introducing re-frame, there were more things to consider. Let’s examine more closely what starting to use re-frame would have meant to us:&lt;/p&gt;

&lt;h4 id=&quot;4-1-from-om-to-reagent&quot;&gt;4. 1. From Om to reagent.&lt;/h4&gt;

&lt;p&gt;re-frame uses &lt;a href=&quot;https://github.com/reagent-project/reagent&quot;&gt;reagent&lt;/a&gt; as its interface to React. Although I personally consider reagent to be much nicer than Om because it feels more ‘Clo­jur­ish’, as it is less verbose and hides React’s complexity better that Om (&lt;a href=&quot;http://theatticlight.net/posts/Om-and-Reagent/&quot;&gt;Om it’s a thinner abstraction over React that reagent&lt;/a&gt;), the amount of view code and components developed using Om during the nearly two years of life of the project made changing to reagent too huge of a change. GreenPowerMonitor had done a heavy investment on Om in our SPA for this change to be advisable.&lt;/p&gt;

&lt;p&gt;If we had chosen to start using re-frame, we would have faced a huge amount of work. Even following a &lt;strong&gt;strangler application pattern&lt;/strong&gt;, it would have taken quite some time to abandon Om, and in the meantime Om and reagent would have had to coexist in our code base. This coexistence would have been problematic because we’d have had to either rewrite some components or add complicated wrapping to reuse Om components from reagent ones. It would have also forced our developers to learn and develop with both technologies.&lt;/p&gt;

&lt;p&gt;Those reasons made us abandon the idea of using re-frame, and chose a less risky and progressive way to get our real goal, which was &lt;strong&gt;having the advantages of re-frame’s architecture in our code&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;5-re-om-is-born&quot;&gt;5. re-om is born.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/andrestylianos&quot;&gt;André&lt;/a&gt; and I decided to do a spike to write an event-driven framework using effects and coeffects. After having a look at re-frame’s code it turned out it wouldn’t be too big of an undertaking. Once we had it done, we called it re-om as a joke.&lt;/p&gt;

&lt;p&gt;At the beginning we had only events with effects and coeffects and started to try it in our code. From the very beginning we saw great improvements in testability and understandability of the code. This original code that was independent of any view technology was improved during several months of use. Most of this code ended being part of &lt;a href=&quot;https://github.com/GreenPowerMonitor/reffectory&quot;&gt;reffectory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later our colleague &lt;a href=&quot;https://github.com/JoelSanchez&quot;&gt;Joel Sánchez&lt;/a&gt; &lt;strong&gt;added subscriptions to re-om&lt;/strong&gt;. This radically changed the way we approach the development of components. They started to become &lt;strong&gt;dumb view code with nearly no logic&lt;/strong&gt; inside, which started to make cumbersome component integration testing nearly unnecessary. Another surprising effect of using re-om was that we were also able to have less and less state inside controls which made things like validations or transformation of the state of controls comprised of other controls much easier.&lt;/p&gt;

&lt;p&gt;A really important characteristic of &lt;strong&gt;re-om is that it’s not invasive&lt;/strong&gt;. Since it was &lt;strong&gt;thought from the very beginning to retrofit a legacy SPA to start using an event-driven architecture with an effects and coeffects system&lt;/strong&gt;, it’s ideal when you want to evolve a code base gradually following a &lt;strong&gt;strangler application pattern&lt;/strong&gt;. The only thing we need to do is initialize re-om passing horizon’s app-state atom. From then on, re-om subscriptions will detect any changes made by the legacy imperative code to re-render the components subscribed to them, and it’ll also be able to use effect handlers we wrote on top of it to mutate the app-state using horizon’s lenses and do other effects that “talk” to the legacy part.&lt;/p&gt;

&lt;p&gt;This way we could start carving islands of pure functional code inside our SPA’s imperative soup, and introduced some sanity to make its development more sustainable.&lt;/p&gt;

&lt;h2 id=&quot;re-om--reffectory&quot;&gt;re-om &amp;amp; reffectory&lt;/h2&gt;

&lt;p&gt;We’ve been using re-om during the last 6 months and it has really made our lives much easier. Before open-sourcing it, we decided to extract from re-om the code that was independent of any view technology. This code is now part of &lt;a href=&quot;https://github.com/GreenPowerMonitor/reffectory&quot;&gt;reffectory&lt;/a&gt; and it might be used as the base for creating frameworks similar to re-om for other view technologies, like for example &lt;a href=&quot;https://github.com/tonsky/rum&quot;&gt;rum&lt;/a&gt;, or even for pure Clojure projects.&lt;/p&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h2&gt;

&lt;p&gt;We’d like to thank &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt; for open-sourcing re-om and reffectory, all our colleagues at GreenPowerMonitor, and the ones that are now in other companies like André and Joel, for using it, giving feedback and contributing to improve it during all this time. We’d also love to thank the re-frame project, which we think is a really wonderful way of writing SPAs and on which we’ve heavily inspired re-om.&lt;/p&gt;

&lt;h2 id=&quot;give-it-a-try&quot;&gt;Give it a try.&lt;/h2&gt;

&lt;p&gt;Please do have a look and try &lt;a href=&quot;https://github.com/GreenPowerMonitor/re-om&quot;&gt;re-om&lt;/a&gt; and &lt;a href=&quot;https://github.com/GreenPowerMonitor/reffectory&quot;&gt;reffectory&lt;/a&gt;. We hope they might be as useful to you as they have been for us.&lt;/p&gt;
</description>
          <pubDate>2018-10-02T21:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/10/re-om</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/10/re-om</guid>
        </item>
      
    
      
        <item>
          <title>Cursos en abierto en Canarias</title>
          <description>&lt;p&gt;En la primera mitad de este año no habíamos podido hacer ningún &lt;a href=&quot;/curso-de-tdd/&quot;&gt;curso de TDD&lt;/a&gt; en abierto. Nos absorbió el trabajo diario, la agenda de eventos en los que participamos, y todas las reuniones, decisiones y papeleos que tuvimos para lanzar nuestra cooperativa. Era una pena porque nos encanta hacer cursos en abierto por el entusiasmo y las ganas de trabajar y de aprender con las que vienen las personas que asisten a ellos. Para nosotros estos cursos son también muy interesantes porque nos permiten conocer a personas, que, en ocasiones, acaban colaborando con Codesai. Ese fue, por ejemplo, mi caso o el de &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Por eso, justo después de &lt;a href=&quot;/2018/07/somos-coop&quot;&gt;constituir la cooperativa&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran&lt;/a&gt; y yo decidimos liarnos la manta a la cabeza y anunciar que haríamos un curso en abierto en Tenerife un mes después, a mitad de Julio, justo antes del comienzo de las vacaciones para muchos. Teníamos muy poco tiempo para anunciarlo, pero era una oportunidad muy buena para empezar a movernos como cooperativa y para seguir refinando el nuevo material que ya habíamos usado en los cursos de TDD que hemos hecho este año en &lt;a href=&quot;/2018/06/merkle-tdd&quot;&gt;Merkle&lt;/a&gt; y &lt;a href=&quot;/2018/08/gradiant-mi-primer-curso-tdd&quot;&gt;Gradiant&lt;/a&gt;. Una vez empezamos a organizarlo, pensé que podría dar otro curso en Gran Canaria con &lt;a href=&quot;https://twitter.com/RonnyAncorini&quot;&gt;Ronny&lt;/a&gt; para aprovechar el viaje. Con lo que al final dimos dos cursos en abierto en una semana: el 9 y 10 de Julio en Las Palmas de Gran Canaria y el 12 y 13 de Julio en Santa Cruz de Tenerife.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_lpgc_2018_1.jpg&quot; alt=&quot;Curso Las Palmas de Gran Canaria 2018 a&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Al curso de Gran Canaria vinieron seis personas. La mayoría de ellas trabajaban en &lt;a href=&quot;https://twitter.com/AIDAsoftware&quot;&gt;AIDA&lt;/a&gt;, una empresa con la que trabajamos durante muchos años y con la que tenemos una relación muy cercana. El curso fue intenso porque el nivel de conocimiento de las personas que vinieron era muy dispar. Trabajamos mucho con las parejas durante los ejercicios prácticos e incluso hicimos una sesión extra una semana después en las oficinas de AIDA en la que terminamos de hacer el &lt;a href=&quot;https://github.com/Codesai/curso-tdd-java/blob/master/katas-java/coffee-machine/README.md&quot;&gt;último ejercicio del curso&lt;/a&gt;. Ronny y yo acabamos muy satisfechos y recibimos muy buen feedback de los asistentes, tanto en persona, como en los formularios para dejar tu opinión de forma anónima que siempre suelo enviar unas semanas después. El curso nos sirvió también para experimentar con algunas nuevas secciones sobre cómo usar dobles de prueba de forma sostenible, y sacamos bastante información para aplicar en próximos cursos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_lpgc_2018_2.jpg&quot; alt=&quot;Curso Las Palmas de Gran Canaria 2018 b&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Al día siguiente volé a Tenerife, donde me esperaba Fran en el aeropuerto, y nos fuimos a su casa donde hicimos los últimos preparativos, y descansamos hasta el día siguiente en que empezaba el curso. Al curso de Tenerife asistieron siete personas que venían de diferentes empresas. La gran mayoría eran personas que habían sido antiguos compañeros de Fran, entre ellos, algunos de sus antiguos mentores, por lo que fue un curso muy especial para él. Yo también disfruté mucho. En este curso el nivel de los asistentes era bastante alto y salieron debates muy interesantes. De nuevo recibimos muy buen feedback al terminar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_tf_2018_1.jpg&quot; alt=&quot;Curso Santa Cruz de Tenerife 2018 a&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Una novedad de estos cursos fue que ofrecimos por primera vez un descuento del 50% para colectivos poco representados en la tecnología. Este descuento es algo que hemos decidido ofrecer de ahora en adelante en nuestros cursos en abierto.&lt;/p&gt;

&lt;p&gt;Viendo los cursos en perspectiva después de unos meses, creo que aprendimos varias cosas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Un mes es muy poco tiempo para promocionar un curso (cómo no ㋡), sobre todo en un mercado tan pequeño como Canarias. Sólo gracias a nuestra red de contactos y a empresas con las que ya habíamos trabajado en el pasado individualmente o como Codesai pudimos conseguir gente suficiente para hacer el curso rentable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;El nuevo material está funcionando bastante bien. Estamos consiguiendo mantener el nivel de satisfacción que había con el curso anterior, al mismo tiempo que estamos pudiendo profundizar en temas que el material anterior no tocaba o lo hacía de forma muy superficial.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Los canales de comunicación que usamos habitualmente para promocionar nuestros cursos, &lt;a href=&quot;https://twitter.com/codesaidev&quot;&gt;Twitter&lt;/a&gt; y &lt;a href=&quot;https://www.linkedin.com/company/codesai/&quot;&gt;LinkedIn&lt;/a&gt; no fueron suficiente para atraer a personas de colectivos poco representados en la tecnología. Sólo dos asistentes aprovecharon el descuento del 50%. Tenemos que buscar otras formas de llegar a estas personas. De hecho, si lees esto y conoces a gente a la que le pudiese interesar, por favor, corre la voz.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personalmente me alegro mucho de haber decidido mover estos cursos, porque he conocido a gente muy interesante y muy agradable con la que espero seguir en contacto, ¡muchas gracias a todos!, por la satisfacción del trabajo en sí mismo, y por los buenos ratos y conversaciones que tuve con mis compañeros Ronny y Fran. Esto es algo que es muy valioso e importante porque al estar distribuidos en diferentes regiones (e incluso países) y trabajar en diferentes clientes se echa de menos el contacto humano con los compañeros. Por eso cada curso y/o cada consultoría presencial que hacemos en pareja es una gran oportunidad para reforzar la relación que nos une. Ronny, Fran, muchísimas gracias por la acogida y todos los buenos ratos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_tf_2018_2.jpg&quot; alt=&quot;Curso Santa Cruz de Tenerife 2018 b&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Antes de terminar quería dar las gracias a &lt;a href=&quot;https://twitter.com/mjtordesillas&quot;&gt;Manuel Tordesillas&lt;/a&gt; por el gran trabajo que hizo preparando todas las &lt;a href=&quot;https://github.com/Codesai/curso-tdd-csharp&quot;&gt;katas del curso en C#&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PS: Nuestro próximo curso en abierto de TDD será el &lt;a href=&quot;https://twitter.com/codesaidev/status/1018803220292997120&quot;&gt;18 y 19 de Octubre en Barcelona&lt;/a&gt;, y de nuevo haremos un descuento del 50% para colectivos poco representados en la tecnología. Corre la voz ㋡&lt;/p&gt;
</description>
          <pubDate>2018-09-04T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/09/tdd_canarias</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/09/tdd_canarias</guid>
        </item>
      
    
      
        <item>
          <title>Gradiant, mi primer Curso de TDD</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_all_group.JPG&quot; alt=&quot;La clase del curso al completo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A principios del pasado Junio volvimos a las oficinas de &lt;a href=&quot;https://www.gradiant.org/&quot;&gt;Gradiant&lt;/a&gt; en Vigo para impartir nuestro &lt;a href=&quot;https://www.codesai.com/curso-de-tdd/&quot;&gt;Curso de TDD&lt;/a&gt;. Gradiant es el acrónimo en inglés del Centro Tecnolóxico de Telecomunicacións de Galicia (Galician Research and Development Center in Advanced Telecommunications). Este centro aplica los conocimientos y experiencia de sus profesionales de investigación para aportar valor a empresas y organizaciones mediante la transferencia de conocimiento y el diseño de productos especializados.&lt;/p&gt;

&lt;p&gt;Además el campus en el que se encuentran sus oficinas está en medio del bosque, y tienen una vista preciosa desde las oficinas. Seguro que compensa el extra de tiempo de desplazamiento.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_landscape.JPG&quot; alt=&quot;Vista del verde paisaje desde las oficinas de Gradiant&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Nos hizo muchísima ilusión cuando nos llamaron para impartir el curso, no sólo porque volvieran a confiar en Codesai para formar a sus desarrolladores, sino también, porque recordamos con mucho cariño el curso de TDD &lt;a href=&quot;/2016/12/estuvimos-en-gradiant&quot;&gt;que impartimos allí a finales de 2016&lt;/a&gt;, de la mano de &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manu Rivero&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis Rovirosa&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En esta ocasión impartimos el curso &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manu Rivero&lt;/a&gt; y yo. Nos gusta impartir nuestros cursos en pareja siempre que podemos porque creemos que el nivel de atención que reciben las parejas durante las sesiones prácticas es mucho mejor. Además dar cursos juntos es una gran oportunidad para trabajar presencialmente y compartir experiencias con compañeros que trabajan normalmente en proyectos diferentes.&lt;/p&gt;

&lt;p&gt;Como habéis podido intuir del título del post, fue mi primer curso de TDD. No soy novato dando formaciones y no me es extraño enfrentarme a esa situación en la que te observa una clase, pero hasta ahora no había tenido la oportunidad de dar nuestro curso de TDD.&lt;/p&gt;

&lt;p&gt;Como os podéis imaginar dar una formación no es llegar allí el primer día y leer las transparencias. El trabajo que lleva detrás es importante, incluso sorprende, porque este tipo de cursos no tienen una gran carga teórica, son muy prácticos. Pero no se trata de prepararse la teoría únicamente, pues en conjunto es muy poco tiempo, sino, sobre todo  de hacer previamente varias veces cada uno de los ejercicios, identificar los puntos de mayor dificultad, discutir las posibles soluciones, y extraer las lecciones de cada uno de ellos.&lt;/p&gt;

&lt;p&gt;Esas lecciones tienen que tener una base firme, porque no se trata solo de detectar que algo te huele mal, o intuir que por ahí van los tiros. Se trata de entender las razones por las que algo es una buena práctica o es una buena decisión de diseño. Profundizar en estos fundamentos y principios me resultó muy útil, no sólo para impartir esta formación, sino también para mi día a día en el trabajo.&lt;/p&gt;

&lt;p&gt;Al final, preparar este curso nos ha llevado unas 8 semanas de trabajo, dedicando algunas horas, fuera de  los proyectos en los que cada uno estamos trabajando.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_selfie.JPG&quot; alt=&quot;Selfie de Antonio en la clase&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ya hablando más concretamente del curso, fue realmente bien. Disfruté mucho viendo trabajar al equipo en cada kata. Como ya pasó en el curso de 2016, la heterogeneidad de los asistentes era muy grande, debido a la gran variedad de proyectos, tecnologías y tipos de sistemas que se desarrollan en Gradiant, (C empotrado para procesado de señales o IOT, APIs REST con Java o node, análisis de datos con Scala, diversas aplicaciones en Java o C++, etc.). Esta diversidad hizo que surgieran conversaciones y debates muy interesantes durante el curso.&lt;/p&gt;

&lt;p&gt;El nivel de los asistentes a este curso fue más alto que el que encontramos en el grupo del curso de Diciembre de 2016. Esto creo que se debe en gran parte a la gran labor que &lt;a href=&quot;https://twitter.com/fer_vilas&quot;&gt;Fernando Vilas&lt;/a&gt; y sus compañeros llevan realizando durante estos últimos años en Gradiant (organizando katas, charlas, etc), y a la vibrante actividad de las comunidades de Vigo.&lt;/p&gt;

&lt;p&gt;Se notaba que habían estado trabajando internamente, porque las bases eran sólidas y pasamos rápido sobre ellas, y esto nos  permitió ir un paso más allá y poder trabajar más en profundidad los detalles de cada ejercicio.&lt;/p&gt;

&lt;p&gt;Esto fue interesante tanto para ellos como para los formadores, ya que nos plantearon preguntas en las que muchas veces había varias respuestas posibles y había que pararse a profundizar un rato entre todos. Conversaciones que fácilmente se extendían a las pausas de los cafés.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_pair.JPG&quot; alt=&quot;Manu trabajando de cerca con cada pareja&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Algunos de los temas que salieron en las charlas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Usar métodos del código de producción en los tests&lt;/li&gt;
  &lt;li&gt;DRY vs WET (Write Explicit Tests).&lt;/li&gt;
  &lt;li&gt;Trabajo de la persona lejos del teclado.&lt;/li&gt;
  &lt;li&gt;Dobles de clases que no son nuestras&lt;/li&gt;
  &lt;li&gt;Crear interfaz del colaborador o no.&lt;/li&gt;
  &lt;li&gt;Equilibrio entre tests de integración vs Unitarios con Dobles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_vigo_tech.JPG&quot; alt=&quot;Antonio participa de unas cañas con parte de la Vigo Tech Alliance&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Como bola extra, la tarde del jueves Fernando nos invitó a acercarnos a un evento de la comunidad de desarrollo de Vigo y me sorprendió lo bien organizada que está. Me contó que durante el año 2017 hubo tal explosión de grupos de desarrollo que vieron la necesidad de organizarse alrededor de lo que han llamado la Vigo Tech Alliance (www.vigotech.org), que si entráis en su página veréis que lo forman nada menos que 15 grupos de tecnología con un calendario tan activo que marea. Mucho que aprender y llevar a las comunidades de desarrollo que hay en Asturias, especialmente a Agile Asturias. (https://www.meetup.com/es-ES/Agile-Asturias/).&lt;/p&gt;

&lt;p&gt;Tanto para Manu como para mi fue un gran placer volver a colaborar con Gradiant.
Muchas gracias por confiar en nosotros de nuevo. Además darle las gracias especialmente a &lt;a href=&quot;https://twitter.com/fer_vilas&quot;&gt;Fernando Vilas&lt;/a&gt; por toda su ayuda. Y por supuesto a Manu por compartir un par de días en un lugar tan fantástico como Vigo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gradiant18_manu_and_antonio.JPG&quot; alt=&quot;Manu y Antonio en el puerto&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2018-08-20T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/08/gradiant-mi-primer-curso-tdd</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/08/gradiant-mi-primer-curso-tdd</guid>
        </item>
      
    
      
        <item>
          <title>Data clumps, primitive obsession and hidden tuples</title>
          <description>&lt;p&gt;During the writing of &lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;one of our posts about connascence&lt;/a&gt; some of us were discussing whether we could consider a &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;data clump&lt;/a&gt; a form of &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;Connascence of Meaning&lt;/a&gt; (CoM) or not. In the end, we agreed that data clumps are indeed a form of CoM and that introducing a class for the missing abstraction reduces their &lt;em&gt;connascence&lt;/em&gt; to &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;Connascence of Type&lt;/a&gt; (CoT).&lt;/p&gt;

&lt;p&gt;I had wondered in the past why we use a similar refactoring to eliminate both &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=9&quot;&gt;primitive obsession&lt;/a&gt; and &lt;em&gt;data clump&lt;/em&gt; smells. Thinking about them from the point of view of &lt;em&gt;connascence&lt;/em&gt; has helped me a lot to understand why. It also gave me an alternative path to get to the same conclusion, in which a &lt;em&gt;data clump&lt;/em&gt; gets basically reduced to &lt;em&gt;an implicit form of primitive obsession&lt;/em&gt;. The reasoning is as  follows:&lt;/p&gt;

&lt;p&gt;The concept of &lt;em&gt;primitive obsession&lt;/em&gt; might be extended to consider the collections that a given language offers as primitives. In such cases, &lt;a href=&quot;http://garajeando.blogspot.com.es/2013/06/encapsulating-collections.html&quot;&gt;encapsulating the collection&lt;/a&gt; reifies a new concept that might attract code that didn’t have where to “live” and thus was scattered all over. From the point of view of &lt;em&gt;connascence&lt;/em&gt;, &lt;em&gt;primitive obsession&lt;/em&gt; is a form of CoM that we transform into CoT by introducing a new type and then we might find &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;Connascence of Algorithm&lt;/a&gt; (CoA) that we’d remove by moving the offending code inside the new type. The composing elements of a data clump only make sense when they go together. This means that &lt;strong&gt;they’re conceptually (but implicitly) grouped&lt;/strong&gt;. In this sense &lt;em&gt;a data clump could be seen as a &lt;strong&gt;“hidden or implicit tuple”&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Having this &lt;strong&gt;“hidden or implicit tuple”&lt;/strong&gt; in mind is now easier to see how closely related the data clump and primitive obsession smells are. In this sense, when we refactor a data clump &lt;strong&gt;&lt;em&gt;what we do is removing the data clump by encapsulating a collection which is its “hidden or implicit tuple”, inside a new class&lt;/em&gt;&lt;/strong&gt;. Again, from the point of view of &lt;em&gt;connascence&lt;/em&gt;, this encapsulation reduces CoM to CoT and might make evident some CoA that will make us move some behavior into the new class that becomes a &lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;value object&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;&lt;em&gt;“hidden or implicit tuple” concept&lt;/em&gt;&lt;/strong&gt; helped me to make more explicit the mental process that was leading me to end up doing very similar refactorings to remove both code smells. I think that CoM unifies both cases much more easily than relating the two smells. The fact that the collection (the grouping of the elements of a data clump) is implicit also makes it more difficult to recognize a data clump as CoM in the first place. That’s why I think that &lt;strong&gt;&lt;em&gt;a data clump is a more implicit example of CoM than primitive obsession&lt;/em&gt;&lt;/strong&gt;, and, thus, we might consider &lt;strong&gt;&lt;em&gt;its CoM to be stronger than the one in primitive obsession&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
</description>
          <pubDate>2018-08-15T04:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/08/hidden-tuples</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/08/hidden-tuples</guid>
        </item>
      
    
      
        <item>
          <title>Improving legacy Om code (II): Using effects and coeffects to isolate effectful code from pure code</title>
          <description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction.&lt;/h3&gt;
&lt;p&gt;In a &lt;a href=&quot;/2018/07/improving-legacy-om-code-1&quot;&gt;previous post&lt;/a&gt;, we applied the &lt;a href=&quot;http://xunitpatterns.com/Humble%20Object.html&quot;&gt;humble object pattern&lt;/a&gt; idea to avoid having to write end-to-end tests for the interesting logic of a hard to test legacy &lt;a href=&quot;https://github.com/omcljs/om&quot;&gt;Om&lt;/a&gt; code, and managed to write cheaper unit tests instead. Then, we saw how those unit tests were far from ideal because they were highly coupled to implementation details, and how these problems were caused by a lack of separation of concerns in the code design.&lt;/p&gt;

&lt;p&gt;In this post we’ll show a solution to those design problems using effects and coeffects that will make the interesting logic pure and, as such, really easy to test and reason about.&lt;/p&gt;

&lt;h3 id=&quot;refactoring-to-isolate-side-effects-and-side-causes-using-effects-and-coeffects&quot;&gt;Refactoring to isolate side-effects and side-causes using effects and coeffects.&lt;/h3&gt;

&lt;p&gt;We refactored the code to isolate side-effects and side-causes from pure logic. This way, not only testing the logic got much easier (the logic would be in pure functions), but also, it made tests less coupled to implementation details. To achieve this we introduced the concepts of coeffects and effects.&lt;/p&gt;

&lt;p&gt;The basic idea of the new design was:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Extracting all the needed data from globals (using coeffects for getting application state, getting component state, getting DOM state, etc).&lt;/li&gt;
  &lt;li&gt;Using pure functions to compute the description of the side effects to be performed (returning effects for updating application state, sending messages, etc) given what was extracted in the previous step (the coeffects).&lt;/li&gt;
  &lt;li&gt;Performing the side effects described by the effects returned by the called pure functions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main difference that the code of &lt;code class=&quot;highlighter-rouge&quot;&gt;horizon.controls.widgets.tree.hierarchy&lt;/code&gt; presented after this refactoring was that the event handler functions were moved back into it again, and that they were using the &lt;em&gt;process-all!&lt;/em&gt; and &lt;em&gt;extract-all!&lt;/em&gt; functions that were used to perform the side-effects described by effects, and extract the values of the side-causes tracked by coeffects, respectively. The event handler functions are shown in the next snippet (to see the whole code click &lt;a href=&quot;https://gist.github.com/trikitrok/03ed9b48d3e9f4942a60a5810347793e&quot;&gt;here&lt;/a&gt;): &lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/ffa05e2a36799d609d8dea84f8b3da46.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Now all the logic in the companion namespace was comprised of pure functions, with neither asynchronous nor mutating code: 
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/f7c5ed3b36bb9fc4eaa07321e078fa78.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Thus, its tests became much simpler:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/0dac9219c32d5cbb60a6b77ca1e7bb0f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how the pure functions receive a map of coeffects already containing all the extracted values they need from the “world” and they return a map with descriptions of the effects. This makes testing really much easier than before, and remove the need to use test doubles.&lt;/p&gt;

&lt;p&gt;Notice also how the test code is now around 100 lines shorter. The main reason for this is that the new tests know much less about how the production code is implemented than the previous one. This made possible to remove some tests that, in the previous version of the code, were testing some branches that we were considering reachable when testing implementation details, but when considering the whole behaviour are actually unreachable.&lt;/p&gt;

&lt;p&gt;Now let’s see the code that is extracting the values tracked by the coeffects:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/01273163c6e93aa4496cf2c0a9ebe556.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which is using several implementations of the &lt;em&gt;Coeffect&lt;/em&gt; protocol:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/d240b2308e76b8127204956f29cb2ac6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;All the coeffects were created using factories to localize in only one place the “shape” of each type of coeffect. This indirection proved very useful when we decided to refactor the code that extracts the value of each coeffect to substitute its initial implementation as a conditional to its current implementation using polymorphism with a protocol.&lt;/p&gt;

&lt;p&gt;These are the coeffects factories:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/3456c8c43f6d734ddf7a68e6b8be3e96.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Now there was only one place where we needed to test side causes (using test doubles for some of them). These are the tests for extracting the coeffects values:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/3b3714472c1766d3b291eb9f782c1846.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;A very similar code is processing the side-effects described by effects:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/aad28ce4569bc4005dfb1e9f36282824.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which uses different effects implementing the &lt;em&gt;Effect&lt;/em&gt; protocol:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/aecfedb1900969558299eecb3ad463dc.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;that are created with the following factories:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/32e1c587af848dc7c4caffe24ccfb77e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Finally, these are the tests for processing the effects:&lt;br /&gt;
&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/a552c25c69d2be1ef032574e1a87ac50.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary.&lt;/h3&gt;

&lt;p&gt;We have seen how by using the concept of effects and coeffects, we were able to refactor our code to get a new design that isolates the effectful code from the pure code. This made testing our most interesting logic really easy because it became comprised of only pure functions.&lt;/p&gt;

&lt;p&gt;The basic idea of the new design was:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Extracting all the needed data from globals (using coeffects for getting application state, getting component state, getting DOM state, etc).&lt;/li&gt;
  &lt;li&gt;Computing in pure functions the description of the side effects to be performed (returning effects for updating application state, sending messages, etc) given what it was extracted in the previous step (the coeffects).&lt;/li&gt;
  &lt;li&gt;Performing the side effects described by the effects returned by the called pure functions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since the time we did this refactoring, we have decided to go deeper in this way of designing code and we’re implementing a full effects &amp;amp; coeffects system inspired by &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements.&lt;/h3&gt;
&lt;p&gt;Many thanks to &lt;a href=&quot;https://twitter.com/zesc&quot;&gt;Francesc Guillén&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/SuuiGD&quot;&gt;Daniel Ojeda&lt;/a&gt;, &lt;a href=&quot;https://github.com/andrestylianos&quot;&gt;André Stylianos Ramos&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/celtric&quot;&gt;Ricard Osorio&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/rojo_angel&quot;&gt;Ángel Rojo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel Ángel Viera&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mjtordesillas&quot;&gt;Manuel Tordesillas&lt;/a&gt; for giving me great feedback to improve this post and for all the interesting conversations.&lt;/p&gt;</description>
          <pubDate>2018-07-21T07:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/07/improving-legacy-om-code-2</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/07/improving-legacy-om-code-2</guid>
        </item>
      
    
      
        <item>
          <title>Somos cooperativa</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/flejesai_tenerife_2018.JPG&quot; alt=&quot;Codesai en Flejesai 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Estamos muy contentos de anunciar que, tras varios meses de papeleos, por fín,
somos una cooperativa. Era un paso que decidimos tomar en nuestro último Flejesai&lt;a href=&quot;#nota1&quot;&gt;*&lt;/a&gt; en Febrero, y que nos parecía muy natural dada la manera en que ya intentábamos funcionar.&lt;/p&gt;

&lt;p&gt;Desde el principio, en Codesai hemos intentado funcionar sin jerarquías, tomando decisiones de una manera horizontal y democrática, y tratando de ser fieles a nuestros principios. Para tomar decisiones tratamos primero de buscar un consenso, que si no conseguimos, resolvemos mediante votación.&lt;/p&gt;

&lt;p&gt;Tomar decisiones de esta manera no es siempre sencillo. Por un lado, debido a la gran cantidad de puntos de vista, este proceso es más ruidoso de lo que suele ser en una empresa más jerárquica. Hay muchas conversaciones para buscar consenso y tomar decisiones. Por otro lado, a veces el grupo no decide lo que a algunas personas les gustaría. Esto lleva a algunas personas a pensar que la búsqueda de consenso no es una forma adecuada de tomar decisiones en una empresa.&lt;/p&gt;

&lt;p&gt;El mayor número de puntos de vista y la cantidad de debate es algo que, al principio, choca cuando uno viene de empresas más tradicionales, pero a lo que uno puede acostumbrarse y con lo que aprende a vivir. Lo que (aparentemente) se pierde en rapidez de decisión, se gana en mayor sentido de pertenencia porque no somos engranajes en una máquina, sino que somos personas con capacidad de influencia y control sobre lo que hacemos como empresa. Por otro lado, aceptar las decisiones del grupo cuando no se toma la decisión que a uno le hubiera gustado, dejar atrás nuestras posiciones iniciales y nuestro ego, y apoyar lo que se ha decidido, exige una gran madurez como personas y como equipo. Además, esta forma de funcionar, requiere también un cambio de mentalidad: ya no somos empleados, ahora somos socios, lo que conlleva un rango de responsabilidades más amplio que el que muchos estábamos acostumbrados a tener o con el que nos sentimos cómodos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/flejesai_tenerife_2018_2.JPG&quot; alt=&quot;Codesai en Flejesai 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;La forma en que funcionamos no es ni mejor ni peor que la forma en que funcionan otras empresas. Son tan sólo las reglas del juego que hemos decidido darnos a nosotros mismos. Cada empresa hace lo que puede. Todas luchamos en contra de las probabilidades, muchas desaparecen después de un tiempo. Nadie puede asegurar que no sigamos el mismo destino, pero, por ahora, aquí seguimos, haciendo todo lo que podemos, con nuestras disfunciones y virtudes, con nuestros éxitos y fracasos, creciendo juntos y sobreviviendo siendo fieles a nuestros principios y valores. En cierta manera, creemos que el mero hecho de que sobrevivamos ya es disruptivo en sí mismo, porque puede servir como una narrativa alternativa&lt;a href=&quot;#nota2&quot;&gt;**&lt;/a&gt; en la que un modelo de empresa de software diferente también puede ser viable.&lt;/p&gt;

&lt;p&gt;Son muchos desafíos juntos. ¿Cómo los estamos resolviendo? Según se nos presentan y como buenamente podemos. No somos perfectos, pero con empatía y paciencia unos con otros vamos mejorando paulatinamente. Es un proceso de aprendizaje conjunto. Aunque reconocemos que aún somos un poco disfuncionales, coincidimos en que Codesai es uno de los grupos más fecundos en los que hemos trabajado.&lt;/p&gt;

&lt;p&gt;En resumen, intentamos hacerlo lo mejor que podemos en cada momento, aprendiendo juntos y disfrutando del camino.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/flejesai_tenerife_2018_3.JPG&quot; alt=&quot;Codesai en Flejesai 3&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;font-size: small;&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; * Los Flejesais son encuentros presenciales que duran varios días que hacemos unas cuantas veces al año.
  &lt;br /&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; ** En &lt;a href=&quot;https://www.goodreads.com/book/show/28048.Hope_in_the_Dark&quot;&gt;Hope in the Dark: Untold Histories, Wild Possibilities&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Rebecca_Solnit&quot;&gt;Rebecca Solnit&lt;/a&gt; profundiza en la idea de la necesidad de disponer de narrativas alternativas a las habituales a la corriente general para inspirar y dar esperanza a más personas haciendo ver que hay más caminos posibles.
&lt;/p&gt;
</description>
          <pubDate>2018-07-17T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/07/somos-coop</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/07/somos-coop</guid>
        </item>
      
    
      
        <item>
          <title>Improving legacy Om code (I): Adding a test harness</title>
          <description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction.&lt;/h3&gt;
&lt;p&gt;I’m working at &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt; as part of a team developing a challenging SPA to monitor and manage renewable energy portfolios using ClojureScript. It’s a two years old &lt;a href=&quot;https://github.com/omcljs/om&quot;&gt;Om&lt;/a&gt; application which contains a lot of legacy code. When I say legacy, I’m using &lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt;’ definition of legacy code as &lt;strong&gt;&lt;em&gt;code without tests&lt;/em&gt;&lt;/strong&gt;. This definition views legacy code from the perspective of &lt;strong&gt;&lt;em&gt;code being difficult to evolve because of a lack of automated regression tests&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-legacy-untested-om-code&quot;&gt;The legacy (untested) Om code.&lt;/h3&gt;
&lt;p&gt;Recently I had to face one of these legacy parts when I had to fix some bugs in the user interface that was presenting all the devices of a given energy facility in a hierarchy tree (devices might be comprised of other devices). This is the original legacy view code:&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/a47fefc77175f5151031380ebc3f4fb5.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;This code contains not only the layout of several components but also the logic to both conditionally render some parts of them and to respond to user interactions. This interesting logic is full of asynchronous and effectful code that is reading and updating the state of the components, extracting information from the DOM itself and reading and updating the global application state. All this makes this code very hard to test.&lt;/p&gt;

&lt;h3 id=&quot;humble-object-pattern&quot;&gt;Humble Object pattern.&lt;/h3&gt;
&lt;p&gt;It’s very difficult to make &lt;a href=&quot;https://garajeando.blogspot.com.es/2017/06/testing-om-components-with-cljs-react.html&quot;&gt;component tests&lt;/a&gt; for non-component code like the one in this namespace, which makes writing end-to-end tests look like the only option.&lt;/p&gt;

&lt;p&gt;However, following the idea of the &lt;a href=&quot;http://xunitpatterns.com/Humble%20Object.html&quot;&gt;humble object pattern&lt;/a&gt;, we might reduce the untested code to just the layout of the view. The &lt;a href=&quot;http://xunitpatterns.com/Humble%20Object.html&quot;&gt;humble object&lt;/a&gt; can be used when a code is too closely coupled to its environment to make it testable. To apply it, the interesting logic is extracted into a separate easy-to-test component that is decoupled from its environment.&lt;/p&gt;

&lt;p&gt;In this case we extracted the interesting logic to a separate namespace, where we thoroughly tested it. With this we avoided writing the slower and more fragile end-to-end tests.&lt;/p&gt;

&lt;p&gt;We wrote the tests using the &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles&quot;&gt;test-doubles&lt;/a&gt; library (I’ve talked about it in &lt;a href=&quot;http://garajeando.blogspot.com.es/2018/04/test-doubles-small-spying-and-stubbing.html&quot;&gt;a recent post&lt;/a&gt;) and some home-made tools that help testing asynchronous code based on &lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the logic we extracted:&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/46253df8ad51894fcd78b5edca0b5540.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;and these are the tests we wrote for it:&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/cfa89cbaddfe44bc5f816b85b4981284.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;See &lt;a href=&quot;https://gist.github.com/trikitrok/a6647dd274e5df3bae2e46ac38a53c50&quot;&gt;here&lt;/a&gt; how the view looks after this extraction. Using the &lt;a href=&quot;http://xunitpatterns.com/Humble%20Object.html&quot;&gt;humble object pattern&lt;/a&gt;, we managed to test the most important bits of logic with fast unit tests instead of end-to-end tests.&lt;/p&gt;

&lt;h3 id=&quot;the-real-problem-was-the-design&quot;&gt;The real problem was the design.&lt;/h3&gt;
&lt;p&gt;We could have left the code as it was (in fact we did for a while), but its tests were highly coupled to implementation details and hard to write because its design was far from ideal. Even though, applying the humble object pattern idea, we had separated the important logic from the view, which allowed us to focus on writing tests with more ROI avoiding end-to-end tests, the extracted logic still contained many concerns. It was not only deciding how to interact with the user and what to render, but also mutating and reading state, getting data from global variables and from the DOM and making asynchronous calls. Its effectful parts were not isolated from its pure parts. This lack of separation of concerns made the code hard to test and hard to reason about, forcing us to use heavy tools: the &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles&quot;&gt;test-doubles&lt;/a&gt; library and our &lt;em&gt;async-test-tools&lt;/em&gt; assertion functions to be able to test the code.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary.&lt;/h3&gt;
&lt;p&gt;First, we applied the humble object pattern idea to manage to write unit tests for the interesting logic of a hard to test legacy Om view, instead of having to write more expensive end-to-end tests. Then, we saw how those unit tests were far from ideal because they were highly coupled to implementation details, and how these problems were caused by a lack of separation of concerns in the code design.&lt;/p&gt;

&lt;h3 id=&quot;next&quot;&gt;Next.&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;/2018/07/improving-legacy-om-code-2&quot;&gt;a future post&lt;/a&gt; we’ll solve the lack of separation of concerns by using effects and coeffects to isolate the logic that decides how to interact with the user from all the effectful code. This new design will make the interesting logic pure and, as such, really easy to test and reason about.&lt;/p&gt;</description>
          <pubDate>2018-07-07T07:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/07/improving-legacy-om-code-1</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/07/improving-legacy-om-code-1</guid>
        </item>
      
    
      
        <item>
          <title>Back at Merkle in 2018</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/merkle_tdd_training_1_2018_a.jpg&quot; alt=&quot;Merkle TDD Training 2018 a&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the last quarter of 2017 we delivered &lt;a href=&quot;/2017/12/we-were-at-merkle-comet&quot;&gt;several TDD trainings at Merkle’s offices in Barcelona&lt;/a&gt; and did several consulting session with their JavaScript and Java teams. &lt;a href=&quot;https://www.merkleinc.com/emea/&quot;&gt;Merkle&lt;/a&gt; is a company with high quality standards for the software they develop, so we were very happy when they contacted us to collaborate again this year doing several TDD trainings and consulting sessions.&lt;/p&gt;

&lt;p&gt;So far we have done the first round of consulting sessions and the first of the TDD trainings. It was a very special one because it was the first test drive of our revamped training material. We have used the feedback from former training attendees to refine our TDD training material. We edited some parts that we thought were less valuable, and added new modules that reflects better the way we understand TDD at Codesai, so that the course is now more dynamic and easier to follow. We are looking forward to having the next consulting sessions and TDD trainings.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;/assets/merkle_tdd_training_1_2018_c.jpg&quot; alt=&quot;Merkle TDD Training 2018 b&quot; /&gt;
  &lt;figcaption&gt;TDD training&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We know that a two days introductory TDD training is not enough for a team to start doing TDD in a real environment. After the training, once the team returns to work, a lot of questions arise and the way to apply TDD is not always clear to them. In order to help Merkle’s teams in this process we are supplementing the TDD training with, on one hand, several rounds of consulting sessions in which we address together the difficulties that arise on the teams daily job, and, on the other hand, with one of the main novelties of this year’s collaboration with Merkle: &lt;strong&gt;a 4 months deliberate practice program&lt;/strong&gt;. This program is aimed to improve the skills of a group of about 22 Merkle’s developers in object-oriented design, refactoring and TDD. We will give more details about it in a future post.&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/merkle_tdd_practice_program_2018_b.jpg&quot; alt=&quot;Merkle TDD Deliberate Practice Program 2018&quot; /&gt;
  &lt;figcaption&gt;Deliberate Practice Program&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Before finishing this post, we would love to thank Merkle (and especially &lt;a href=&quot;https://www.linkedin.com/in/nelsoncardenas/&quot;&gt;Nelson Cardenas&lt;/a&gt;) for trusting us again to train their developers and help them grow their skills.&lt;/p&gt;
</description>
          <pubDate>2018-06-26T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/06/merkle-tdd</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/06/merkle-tdd</guid>
        </item>
      
    
      
        <item>
          <title>Socrates Canaries 2018</title>
          <description>&lt;p&gt;This year, I had the pleasure to attend my second &lt;a href=&quot;http://socracan.com/&quot;&gt;Socracan&lt;/a&gt;, an unconference organised in the Canary Islands that brings together people from the Craft Community. This conference had been organised in the past by the &lt;a href=&quot;http://softwarecraftsmanshipgc.github.io/&quot;&gt;Software Crafters community&lt;/a&gt; in Canary Islands and most of the great groundwork done by them has been really helpful in. On this point I would like to give my personal perspective as an organiser jumping from the bench.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/socracan2018.jpg&quot; alt=&quot;Socracan 2018&quot; /&gt;
    &lt;figcaption&gt;Thanks &lt;a href=&quot;https://twitter.com/bberrycarmen&quot;&gt;Rachel&lt;/a&gt; for the picture.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As I live away from the islands, I could not help with most of the preparations that took place before the event. I would like to thank my colleagues &lt;a href=&quot;https://www.linkedin.com/in/dácil-c-8b587a37&quot;&gt;Dácil&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel&lt;/a&gt; for that. My objective was to be of support at the event and I have to say that apart from providing materials and setting a few things up I had not much else to do. That is something I did not expect and I believe that is one of the great things of this event.&lt;/p&gt;

&lt;p&gt;When you have such a great facilitator as &lt;a href=&quot;https://twitter.com/eidrien&quot;&gt;Adrian Perreau&lt;/a&gt; and such a great group of attendees, magic is there just waiting to happen and every moment lived with the group is a learning opportunity. I would like to thank &lt;a href=&quot;https://twitter.com/w3ltraumpirat&quot;&gt;Tobias Goeschel&lt;/a&gt; for helping with the Open Space rules, &lt;a href=&quot;https://twitter.com/jason_peper&quot;&gt;Jason Peper&lt;/a&gt; for always going the extra mile and publishing the program online, &lt;a href=&quot;https://twitter.com/rubendm23&quot;&gt;Rubén&lt;/a&gt; for becoming another backup organiser just like me and everyone else that attended because in the end, the community is what makes the event worth it :)&lt;/p&gt;

&lt;p&gt;As with any event, not only the talks and workshops are the only opportunities for taking a learning pill back home. Conversations in the halls, on the beach, over dinner or over coffee are one of the reasons why I will be back next year. The quality of the talks was amazing and with many formats, there were roundtables to share experiences about remote working, creating a community with a culture of learning and how the movement can become more inclusive. &lt;a href=&quot;https://twitter.com/wolframkriesing&quot;&gt;Wolfram Kriesing&lt;/a&gt; presented us his experience in teaching TDD to kids taking away all the noise and boiling it down into a spreadsheet and &lt;a href=&quot;https://twitter.com/w3ltraumpirat&quot;&gt;Tobias&lt;/a&gt; made a great Event Storming express workshop.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/heisenberg-rocks.jpg&quot; alt=&quot;Heisenberg Rocks&quot; /&gt;
    &lt;figcaption&gt;Thanks &lt;a href=&quot;https://twitter.com/EvAltenberga&quot;&gt;Eddie&lt;/a&gt; for the picture.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;But at Socracan there was also time for partying! Our colleague &lt;a href=&quot;https://www.linkedin.com/in/dácil-c-8b587a37&quot;&gt;Dácil&lt;/a&gt; and her band &lt;a href=&quot;https://www.facebook.com/pg/HeisenbergRockBand/posts/&quot;&gt;Heisenberg&lt;/a&gt; rocked the stage in one of most iconic venues in the city. Thanks &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;Carlos&lt;/a&gt; for organising it :)&lt;/p&gt;

&lt;p&gt;As with any event, there were things that worked better than others. That is why we have written down all the feedback given during and after the event, and we are open to any suggestions for the next event. See you next year :)&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/retrospective.jpg&quot; alt=&quot;Restrospective on the beach&quot; /&gt;
    &lt;figcaption&gt;Thanks &lt;a href=&quot;https://twitter.com/woditschka&quot;&gt;Bernard&lt;/a&gt; for the picture.&lt;/figcaption&gt;
&lt;/figure&gt;
</description>
          <pubDate>2018-06-14T09:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/06/socracan-18</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/06/socracan-18</guid>
        </item>
      
    
      
        <item>
          <title>Improve your reds</title>
          <description>&lt;p&gt;Improving your reds is a simple tip that is described by &lt;a href=&quot;https://www.linkedin.com/in/stevefreeman&quot;&gt;Steve Freeman&lt;/a&gt; and &lt;a href=&quot;http://www.natpryce.com/&quot;&gt;Nat Pryce&lt;/a&gt; in their wonderful book &lt;a href=&quot;https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests&quot;&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It consists in a small variation to the TDD cycle in which you watch the error message of your failing test and ask yourself if the information it gives you would make it easier to diagnose the origin of the problem in case this error appears as a regression in the future. If the answer is no, you improve the error message before going on to make the test pass.&lt;/p&gt;

&lt;figure style=&quot;height:40%; width:40%;&quot;&gt;
    &lt;img src=&quot;/assets/feedback-on-diagnostics.svg&quot; alt=&quot;Variation to TDD cycle: feedback on diagnostics&quot; /&gt;
    &lt;figcaption&gt;
      From Growing Object-Oriented Software by Nat Pryce and Steve Freeman.
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Investing time in improving your reds will prove very useful for your colleagues and yourself because the clearer the error message, the better the context to fix the regression error effectively. Most of the times, applying this small variation to the TDD cycle only requires a small effort.&lt;/p&gt;

&lt;p&gt;As a simple example, have a look at the following assertion and how it fails&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.AssertionError:
Expected: is &amp;lt;Fraction@2d8e8c3a&amp;gt;
     but: was &amp;lt;Fraction@2d8e84b8&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Why is it failing? Will this error message help us know what’s happening if we see it in the future?&lt;/p&gt;

&lt;p&gt;The answer is clearly &lt;em&gt;no&lt;/em&gt;, but with little effort, we can add a bit of code to make the error message clearer (implementing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString()&lt;/code&gt; method).&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Fraction{&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;numerator=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numerator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;, denominator=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;denominator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;sc&quot;&gt;&apos;}&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.AssertionError:
Expected: is &amp;lt;Fraction{numerator=3, denominator=2}&amp;gt;
     but: was &amp;lt;Fraction{numerator=1, denominator=2}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This error message is much clearer than the previous one and will help us to be more effective both while test-driving the code and if/when a regression error happens in the future, and we got this just by adding an implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString()&lt;/code&gt; generated by our IDE.&lt;/p&gt;

&lt;p&gt;Take that low hanging fruit. Start improving your reds!&lt;/p&gt;
</description>
          <pubDate>2018-06-08T09:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/06/improving-your-reds</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/06/improving-your-reds</guid>
        </item>
      
    
      
        <item>
          <title>A small spying and stubbing library for Clojure and ClojureScript: test-doubles</title>
          <description>&lt;div style=&quot;text-align: justify;&quot;&gt;
As you may know from a &lt;a href=&quot;https://www.codesai.com/2017/06/testing-om-components&quot;&gt;previous post&lt;/a&gt; I&amp;#8217;m working for &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt;
as part of a team that is developing a challenging SPA to monitor and manage renewable energy portfolios using ClojureScript.
&lt;/div&gt;
&lt;br&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
We were dealing with some legacy code that was effectful and needed to be tested using &lt;a href=&quot;http://xunitpatterns.com/Test%20Double.html&quot;&gt;test doubles&lt;/a&gt;, 
so we explored some existing ClojureScript libraries but we didn&apos;t feel comfortable with them. On one hand, we found that some of them had different macros for different types of test doubles and this made tests that needed both spies and stubs become very nested. We wanted to produce tests with as little nesting as possible. On the other hand, being used to &lt;a href=&quot;https://martinfowler.com/bliki/TestDouble.html&quot;&gt;Gerard Meszaros&amp;#8217; vocabulary for tests doubles&lt;/a&gt;, we found the naming used for different types of tests doubles in some of the existing libraries a bit confusing. We wanted to stick to &lt;a href=&quot;https://martinfowler.com/bliki/TestDouble.html&quot;&gt;Gerard Meszaros&amp;#8217; vocabulary for tests doubles&lt;/a&gt;. 
&lt;/div&gt;
&lt;br&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
So we decided we&apos;d write our own &lt;a href=&quot;http://xunitpatterns.com/Test%20Stub.html&quot;&gt;stubs&lt;/a&gt; and &lt;a href=&quot;http://xunitpatterns.com/Test%20Spy.html&quot;&gt;spies&lt;/a&gt; library. 
&lt;/div&gt;
&lt;br&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
We started by manually creating our own spies and stubs during some time so that we could identify the different ways in which we were going to use them. After a while, my colleague &lt;a href=&quot;https://github.com/andrestylianos&quot;&gt;André Stylianos Ramos&lt;/a&gt; and I wrote our own small DSL to create stubs and spies using macros to remove all that duplication and boiler plate. The result was a small library that we&apos;ve been using in our ClojureScript project for nearly a year and that we&apos;ve recently adapted to make it work in Clojure as well: 
&lt;/div&gt;
&lt;br&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/5ed98db6faa4f7a6390ab422a3aed280.js&quot;&gt;&lt;/script&gt;

&lt;div style=&quot;text-align: justify;&quot;&gt;
I&amp;#8217;m really glad to announce that &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;GreenPowerMonitor&lt;/a&gt; has open-sourced our small spying and stubbing library for Clojure and ClojureScript: &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles&quot;&gt;test-doubles&lt;/a&gt;.
&lt;/div&gt;
&lt;br&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
In the following example written in ClojureScript, we show how we are using &lt;code&gt;test-doubles&lt;/code&gt; to create two &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles/blob/master/README.md#1-stubbing-function-calls&quot;&gt;stubs&lt;/a&gt; (one with the &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles/blob/master/README.md#13-maps&quot;&gt;:maps option&lt;/a&gt; and another with the &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles/blob/master/README.md#11-returns-option&quot;&gt;:returns option&lt;/a&gt;) and a &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles/blob/master/README.md#2-spying-function-calls&quot;&gt;spy&lt;/a&gt;:
&lt;/div&gt;
&lt;br&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/4a6a2f9f1ac41932bb467cb1f80fed4e.js&quot;&gt;&lt;/script&gt;

&lt;div style=&quot;text-align: justify;&quot;&gt;
We could show you more examples here of how &lt;code&gt;test-doubles&lt;/code&gt; can be used and the different options it provides, but we&amp;#8217;ve already included a lot of explained examples in its &lt;a href=&quot;https://github.com/GreenPowerMonitor/test-doubles/blob/master/README.md&quot;&gt;documentation&lt;/a&gt;.
&lt;/div&gt;
&lt;br&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Please do have a look and try our library. You can get its &lt;a href=&quot;https://clojars.org/greenpowermonitor/test-doubles&quot;&gt;last version from Clojars&lt;/a&gt;. We hope it might be as useful to you as it has been for us.
&lt;/div&gt;</description>
          <pubDate>2018-04-21T21:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/04/test-doubles-small-spying-and-stubbing</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/04/test-doubles-small-spying-and-stubbing</guid>
        </item>
      
    
      
        <item>
          <title>A small kata to explore and play with property-based testing</title>
          <description>&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h3&gt;

&lt;p&gt;I’ve been reading &lt;a href=&quot;https://twitter.com/mononcqc?lang=en&quot;&gt;Fred Hebert&lt;/a&gt;’s wonderful &lt;a href=&quot;https://propertesting.com/&quot;&gt;PropEr Testing online book&lt;/a&gt; about &lt;a href=&quot;https://ferd.ca/property-based-testing-basics.html&quot;&gt;property-based testing&lt;/a&gt;. So to play with it a bit, I did a small exercise. This is its description:&lt;/p&gt;

&lt;h4 id=&quot;1-1-the-kata&quot;&gt;1. 1. The kata.&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;We’ll implement a function that can tell if two sequences are equal regardless of the order of their elements. The elements can be of any type.&lt;/p&gt;

  &lt;p&gt;We’ll use property-based testing (PBT). Use the PBT library of your language (bring it already installed).
Follow these constraints:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;You can’t use or compute frequencies of elements.&lt;/li&gt;
    &lt;li&gt;Work test first: write a test, then write the code to make that test pass.&lt;/li&gt;
    &lt;li&gt;If you get stuck, you can use example-based tests to drive the implementation on. However, at the end of the exercise, only property-based tests can remain.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Use mutation testing to check if you tests are good enough (we’ll do it manually injecting failures in the implementation code (by commenting or changing parts of it) and checking if the test are able to detect the failure to avoid using more libraries).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;2-driving-a-solution-using-both-example-based-and-property-based-tests&quot;&gt;2. Driving a solution using both example-based and property-based tests.&lt;/h3&gt;

&lt;p&gt;I used &lt;em&gt;Clojure&lt;/em&gt; and its &lt;a href=&quot;https://github.com/clojure/test.check&quot;&gt;test.check&lt;/a&gt; library (an implementation of &lt;a href=&quot;https://en.wikipedia.org/wiki/QuickCheck&quot;&gt;QuickCheck&lt;/a&gt;) to do the exercise. I also used my favorite &lt;em&gt;Clojure&lt;/em&gt;’s test framework: &lt;a href=&quot;https://twitter.com/marick&quot;&gt;Brian Marick&lt;/a&gt;’s &lt;a href=&quot;https://github.com/marick/Midje&quot;&gt;Midje&lt;/a&gt; which has a macro, &lt;a href=&quot;https://github.com/marick/Midje/wiki/Generative-testing-with-for-all&quot;&gt;forall&lt;/a&gt;, which makes it very easy to integrate property-based tests with &lt;em&gt;Midje&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I started to drive a solution using an example-based test (thanks to &lt;em&gt;Clojure&lt;/em&gt;’s dynamic nature, I could use vectors of integers to write the tests.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/bb1d7884fc8b418ef58a35d3ecc789e7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which I made pass using the following implementation:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3497e9be659a4adefac191985152ce84.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then I wrote a property-based test that failed:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/dde083a0743a3640377c48e4395aef66.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is how the failure looked in &lt;em&gt;Midje&lt;/em&gt; (&lt;em&gt;test.check&lt;/em&gt; returns more output when a property fails, but &lt;em&gt;Midje&lt;/em&gt; extracts and shows only the information it considers more useful):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/22c72ad72d7703d157708b01cbf43cfb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;the most useful piece of information for us in this failure message is &lt;strong&gt;the quick-check shrunken failing values&lt;/strong&gt;. When a property-based testing library finds a counter-example for a property, it applies a &lt;strong&gt;shrinking algorithm&lt;/strong&gt; which  tries to reduce it to &lt;strong&gt;find a minimal counter-example that produces the same test failure&lt;/strong&gt;. 
In this case, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1 0]&lt;/code&gt; vector is the minimal counter-example found by the &lt;strong&gt;shrinking algorithm&lt;/strong&gt; that makes this test fails.&lt;/p&gt;

&lt;p&gt;Next I made the property-based test pass by refining the implementation a bit:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/fd93859bf9aca2db7f683e40bc3ff649.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I didn’t know which property to write next, so I wrote a failing example-based test involving duplicate elements instead:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/374cabad9d1d02885b574776ef5d87f1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and refined the implementation to make it pass:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/00575377dd651b18cd15efd7371b11af.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;With this, the implementation was done (I chose a function that was easy to implement, so I could focus on thinking about properties).&lt;/p&gt;

&lt;h3 id=&quot;3-getting-rid-of-example-based-tests&quot;&gt;3. Getting rid of example-based tests.&lt;/h3&gt;

&lt;p&gt;Then the next step was finding properties that could make the example-based tests redundant. I started by trying to remove the first example-based test. Since I didn’t know &lt;em&gt;test.check&lt;/em&gt;’s generators and combinators library, I started exploring it on the REPL with the help of its &lt;a href=&quot;http://clojure.github.io/test.check/&quot;&gt;API documentation&lt;/a&gt; and &lt;a href=&quot;https://github.com/clojure/test.check/blob/master/doc/cheatsheet.md&quot;&gt;cheat sheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My sessions on the REPL to build generators bit by bit were a process of shallowly reading bits of documentation followed by trial and error. This tinkering sometimes lead to quick successes and most of the times to failures which lead to more deep and careful reading of the documentation, and more trial and error. In the end I managed to build the generators I wanted. The &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-sample&quot;&gt;sample&lt;/a&gt; function was very useful during all the process to check what each part of the generator would generate.&lt;/p&gt;

&lt;p&gt;For the sake of brevity I will show only summarized versions of my REPL sessions where everything seems easy and linear…&lt;/p&gt;

&lt;h4 id=&quot;3-1-first-attempt-a-partial-success&quot;&gt;3. 1. First attempt: a partial success.&lt;/h4&gt;

&lt;p&gt;First, I wanted to create a generator that generated two different vectors of integers so that I could replace the  example-based tests that were checking two different vectors. I used the &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-list-distinct&quot;&gt;list-distinct combinator&lt;/a&gt; to create it and the &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-sample&quot;&gt;sample&lt;/a&gt; function to be able to see what the generator would generate:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ce12295941fcf6aa20181b2537944fe2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I used this generator to write a new property which made it possible to remove the first example-based test but not the second one:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/647c484b69394507a501fcea1ddd5fb4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In principle, we might think that the new property should have been enough to also allow removing the last example-based test involving duplicate elements. A quick manual mutation test, after removing that example-based test, showed that it wasn’t enough: I commented the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(= (count s1) (count s2))&lt;/code&gt; in the implementation and the property-based tests weren’t able to detect the regression.&lt;/p&gt;

&lt;p&gt;This was due to the low probability of generating a pair of random vectors that were different because of having duplicate elements, which was what the commented line, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(= (count s1) (count s2))&lt;/code&gt;, was in the implementation for. If we’d run the tests more times, we’d have finally won the lottery of generating a counter-example that would detect the regression. So we had to improve the generator in order to increase the probabilities, or, even better, make sure it’d be able to detect the regression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice, we’d pragmatically combine example-based and property-based tests if we needed to&lt;/strong&gt;. However, my goal was learning more about property-based testing, so I went on and tried to improve the generators (that’s why this exercise has the constraint of using only property-based tests).&lt;/p&gt;

&lt;h4 id=&quot;3-2-second-attempt-success&quot;&gt;3. 2. Second attempt: success!&lt;/h4&gt;

&lt;p&gt;So, I worked a bit more on the REPL with the goal of &lt;strong&gt;creating a generator that would always generate vectors with duplicate elements&lt;/strong&gt;. For that I used &lt;em&gt;test.check&lt;/em&gt;’s &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-let&quot;&gt;let&lt;/a&gt; macro, the &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-tuple&quot;&gt;tuple&lt;/a&gt;, &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-such-that&quot;&gt;such-that&lt;/a&gt; and &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-not-empty&quot;&gt;not-empty&lt;/a&gt; combinators, and &lt;em&gt;Clojure&lt;/em&gt;’s core library &lt;a href=&quot;https://clojuredocs.org/clojure.core/repeat&quot;&gt;repeat&lt;/a&gt; function to build it.&lt;/p&gt;

&lt;p&gt;The following snippet shows a summary of the work I did on the REPL to create the generator using again the &lt;a href=&quot;http://clojure.github.io/test.check/clojure.test.check.generators.html#var-sample&quot;&gt;sample&lt;/a&gt; function at each tiny step to see what inputs the growing generator would generate:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ff53dddf80f399f53223c8bd62885def.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Next I used this new generator to write properties that this time did detect the regression mentioned above. Notice how there are separate properties for sequences with and without duplicates:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2c9f8fecb53d14f66fc4b3bab75557d0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Finally, I managed to remove a redundant property-based test and got to this final version:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/aa40f03466b2bc2c3f088e2f9b2af535.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;4-conclusion&quot;&gt;4. Conclusion.&lt;/h3&gt;

&lt;p&gt;All in all, this exercise was very useful to think about properties and to explore &lt;em&gt;test.check&lt;/em&gt;’s generators and combinators. Using the REPL made this exploration very interactive and a lot of fun. You can find &lt;a href=&quot;https://github.com/trikitrok/same-not-regarding-order-kata-clojure&quot;&gt;the code of this exercise on this GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A couple of days later I proposed to solve this exercise at the last &lt;a href=&quot;https://www.meetup.com/ClojureBCN/events/248734726/&quot;&gt;Clojure Developers Barcelona meetup&lt;/a&gt;. I received very positive feedback, so I’ll probably propose it for a &lt;a href=&quot;https://www.meetup.com/Barcelona-Software-Craftsmanship/&quot;&gt;Barcelona Software Craftsmanship meetup&lt;/a&gt; event soon.&lt;/p&gt;

</description>
          <pubDate>2018-04-11T11:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/04/kata-small-exercise-to-explore-and-play</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/04/kata-small-exercise-to-explore-and-play</guid>
        </item>
      
    
      
        <item>
          <title>Examples lists in TDD</title>
          <description>&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction.&lt;/h3&gt;

&lt;p&gt;During coding dojos and some mentoring sessions I’ve noticed that most people just start test-driving code without having thought a bit about the problem first. Unfortunately, &lt;strong&gt;writing a list of examples&lt;/strong&gt; before starting to do TDD is a practice that is most of the times neglected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing a list of examples&lt;/strong&gt; is very useful because having to find a list of concrete examples forces you to think about the problem at hand. In order to write each concrete example in the list, you need to understand what you are trying to do and how you will know when it is working. This exploration of the problem space improves your knowledge of the domain, which will later be very useful while doing TDD to design a solution. However, just generating a list of examples is not enough.&lt;/p&gt;

&lt;h3 id=&quot;2-orthogonal-examples&quot;&gt;2. Orthogonal examples.&lt;/h3&gt;

&lt;p&gt;A frequent problem I’ve seen in beginners’ lists is that many of the examples are redundant because they would drive the same piece of behavior. When two examples drive the same behavior, we say that they overlap with each other, they are overlapping examples.&lt;/p&gt;

&lt;p&gt;To explore the problem space effectively, we need to find examples that drive different pieces of behavior, i.e. that do not overlap. From now on, I will refer to those non-overlapping examples as &lt;strong&gt;orthogonal examples&lt;/strong&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Keeping this idea of &lt;strong&gt;orthogonal examples&lt;/strong&gt; in mind while exploring a problem space, will help us prune examples that don’t add value, and keep just the ones that will force us to drive new behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can we get those orthogonal examples?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Start by writing all the examples that come to your mind.&lt;/li&gt;
  &lt;li&gt;As you gather more examples ask yourself which behavior they would drive. Will they drive one clear behavior or will they drive several behaviors?&lt;/li&gt;
  &lt;li&gt;Try to group them by the piece of behavior they’d drive and see which ones overlap so you can prune them.&lt;/li&gt;
  &lt;li&gt;Identify also which behaviors of the problem are not addressed by any example yet. This will help you find a list of orthogonal examples.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With time and experience you’ll start seeing these behavior partitions in your mind and spend less time to find orthogonal examples.&lt;/p&gt;

&lt;h3 id=&quot;3-a-concrete-application&quot;&gt;3. A concrete application.&lt;/h3&gt;

&lt;p&gt;Next, we’ll explore a concrete application using a subset of the &lt;em&gt;Mars Rover kata&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The rover is located on a grid at some point with coordinates (x,y) and facing a direction encoded with a character.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The meaning of each direction character is:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;N&quot;&lt;/code&gt; -&amp;gt; North&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;S&quot;&lt;/code&gt; -&amp;gt; South&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;E&quot;&lt;/code&gt; -&amp;gt; East&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;W&quot;&lt;/code&gt; -&amp;gt; West&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The rover receives a sequence of commands (a string of characters) which are codified in the following way:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;When it receives an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;f&quot;&lt;/code&gt;, it moves forward one position in the direction it is facing.&lt;/li&gt;
      &lt;li&gt;When it receives a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;b&quot;&lt;/code&gt;, it moves backward one position in the direction it is facing.&lt;/li&gt;
      &lt;li&gt;When it receives a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;l&quot;&lt;/code&gt;, it turns 90º left changing its direction.&lt;/li&gt;
      &lt;li&gt;When it receives a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;r&quot;&lt;/code&gt;, it turns 90º right changing its direction.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start writing a list of examples that explores this problem. But how?&lt;/p&gt;

&lt;p&gt;Since the rover is receiving a sequence of commands, we can apply a useful heuristic for sequences to get us started: &lt;a href=&quot;https://twitter.com/jbrains?lang=en&quot;&gt;J. B. Rainsberger&lt;/a&gt;’s &lt;strong&gt;“0, 1, many, oops” heuristic&lt;/strong&gt; &lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case, it means generating examples for: &lt;strong&gt;no commands&lt;/strong&gt;, &lt;strong&gt;one command&lt;/strong&gt;, &lt;strong&gt;several commands&lt;/strong&gt; and &lt;strong&gt;unknown commands&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I will use the following notation for examples:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(x, y, d), commands_sequence -&amp;gt; (x’, y’, d’)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Meaning that, given the rover is in an initial location with &lt;em&gt;x&lt;/em&gt; and &lt;em&gt;y&lt;/em&gt; coordinates, and facing a direction &lt;em&gt;d&lt;/em&gt;, after receiving a given sequence of commands (which is represented by a string), the rover will be located at &lt;em&gt;x’&lt;/em&gt; and &lt;em&gt;y&lt;/em&gt;’ coordinates and facing the &lt;em&gt;d’&lt;/em&gt; direction.&lt;/p&gt;

&lt;p&gt;Then our first example corresponding to &lt;strong&gt;no commands&lt;/strong&gt; might be any of:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(0, 0, &quot;N&quot;), &quot;&quot; -&amp;gt; (0, 0, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1, 4, &quot;S&quot;), &quot;&quot; -&amp;gt; (1, 4, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2, 5, &quot;E&quot;), &quot;&quot; -&amp;gt; (2, 5, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(3, 2, &quot;E&quot;), &quot;&quot; -&amp;gt; (3, 2, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
…&lt;/p&gt;

&lt;p&gt;Notice that in these examples, we don’t care about the specific positions or directions of the rover. The only important thing here is that the position and direction of the rover does not change. They will all drive the same behavior so we might express this fact using a more generic example:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, any_direction), &quot;&quot; -&amp;gt; (any_x, any_y, any_direction)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where we have used &lt;em&gt;any_x&lt;/em&gt;, &lt;em&gt;any_y&lt;/em&gt; and &lt;em&gt;any_direction&lt;/em&gt; to make explicit that the specific values that &lt;em&gt;any_x&lt;/em&gt;, &lt;em&gt;any_y&lt;/em&gt; and &lt;em&gt;any_direction&lt;/em&gt; take are not important for these tests. What is important for the tests, is that the values of &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; and &lt;em&gt;direction&lt;/em&gt; remain the same after applying the sequence of commands &lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we focus on receiving &lt;strong&gt;one command&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this case there are a lot of possible examples, but we are only interested on those that are orthogonal. Following our recommendations to get orthogonal examples, you can get to the following set of 16 examples that can be used to drive all the &lt;strong&gt;one command&lt;/strong&gt; behavior (we’re using &lt;em&gt;any_x&lt;/em&gt;, &lt;em&gt;any_y&lt;/em&gt; where we can):&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4, any_y, &quot;E&quot;), &quot;b&quot; -&amp;gt; (3, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;S&quot;), &quot;l&quot; -&amp;gt; (any_x, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 6, &quot;N&quot;), &quot;b&quot; -&amp;gt; (any_x, 5, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 3, &quot;N&quot;), &quot;f&quot; -&amp;gt; (any_x, 4, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(5, any_y, &quot;W&quot;), &quot;f&quot; -&amp;gt; (4, any_y, &quot;W&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2, any_y, &quot;W&quot;), &quot;b&quot; -&amp;gt; (3, any_y, &quot;W&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;E&quot;), &quot;l&quot; -&amp;gt; (any_x, any_y, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;W&quot;), &quot;r&quot; -&amp;gt; (any_x, any_y, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;N&quot;), &quot;l&quot; -&amp;gt; (any_x, any_y, &quot;W&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1, any_y, &quot;E&quot;), &quot;f&quot; -&amp;gt; (2, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 8, &quot;S&quot;), &quot;f&quot; -&amp;gt; (any_x, 7, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;E&quot;), &quot;r&quot; -&amp;gt; (any_x, any_y, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 3, &quot;S&quot;), &quot;b&quot; -&amp;gt; (any_x, 4, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;W&quot;), &quot;l&quot; -&amp;gt; (any_x, any_y, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;N&quot;), &quot;r&quot; -&amp;gt; (any_x, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;S&quot;), &quot;r&quot; -&amp;gt; (any_x, any_y, &quot;W&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There’re already important properties about the problem that we can learn from these examples:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The position of the rover is irrelevant for rotations.&lt;/li&gt;
  &lt;li&gt;The direction the rover is facing is relevant for every command. It determines how each command will be applied.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes it can also be useful to think in different ways of grouping the examples to see how they may relate to each other.&lt;/p&gt;

&lt;p&gt;For instance, we might group the examples above &lt;strong&gt;by the direction the rover faces initially&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Facing East&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1, any_y, &quot;E&quot;), &quot;f&quot; -&amp;gt; (2, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4, any_y, &quot;E&quot;), &quot;b&quot; -&amp;gt; (3, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;E&quot;), &quot;l&quot; -&amp;gt; (any_x, any_y, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, &quot;E&quot;), &quot;r&quot; -&amp;gt; (any_x, any_y, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;strong&gt;Facing West&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(5, any_y, &quot;W&quot;), &quot;f&quot; -&amp;gt; (4, any_y, &quot;W&quot;)&lt;/code&gt; …&lt;/p&gt;

&lt;p&gt;or, &lt;strong&gt;by the command the rover receives&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move forward&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(1, any_y, &quot;E&quot;), &quot;f&quot; -&amp;gt; (2, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(5, any_y, &quot;W&quot;), &quot;f&quot; -&amp;gt; (4, any_y, &quot;W&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 3, &quot;N&quot;), &quot;f&quot; -&amp;gt; (any_x, 4, &quot;N&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, 8, &quot;S&quot;), &quot;f&quot; -&amp;gt; (any_x, 7, &quot;S&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;strong&gt;Move backward&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4, any_y, &quot;E&quot;), &quot;b&quot; -&amp;gt; (3, any_y, &quot;E&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(2, any_y, &quot;W&quot;), &quot;b&quot; -&amp;gt; (3, any_y, &quot;W&quot;)&lt;/code&gt;&lt;br /&gt;
…&lt;/p&gt;

&lt;p&gt;Trying to classify the examples helps us explore different ways in which we can use them to make the code grow by discovering what &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt; calls &lt;strong&gt;dimensions of complexity&lt;/strong&gt; of the problem&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. Each dimension of complexity can be driven using a different set of orthogonal examples, so this knowledge can be useful to choose the next example when doing TDD.&lt;/p&gt;

&lt;p&gt;Which of the two groupings shown above might be more useful to drive the problem?&lt;/p&gt;

&lt;p&gt;In this case, I think that the &lt;strong&gt;by the command the rover receives&lt;/strong&gt; grouping is more useful, because each group will help us drive a whole behavior (the command). If we were to use the &lt;strong&gt;by the direction the rover faces initially&lt;/strong&gt; grouping, we’d end up with partially implemented behaviors (commands) after using each group of examples.&lt;/p&gt;

&lt;p&gt;Once we have the &lt;strong&gt;one command&lt;/strong&gt; examples, let’s continue using the &lt;strong&gt;“0, 1, many, oops” heuristic&lt;/strong&gt; and find examples for the &lt;strong&gt;several commands&lt;/strong&gt; category.&lt;/p&gt;

&lt;p&gt;We can think of many different examples:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(7, 4, &quot;E&quot;), &quot;rb&quot; -&amp;gt; (7, 5, &quot;S&quot;)&lt;/code&gt; 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(7, 4, &quot;E&quot;), &quot;fr&quot; -&amp;gt; (8, 4, &quot;S&quot;)&lt;/code&gt; 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(7, 4, &quot;E&quot;), &quot;ffl&quot; -&amp;gt; (9, 4, &quot;N&quot;)&lt;/code&gt; 
…&lt;/p&gt;

&lt;p&gt;The thing is that any of them might be thought as a composition of several commands:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(7, 4, &quot;E&quot;), &quot;r&quot; -&amp;gt; (7, 4, &quot;S&quot;), &quot;b&quot; -&amp;gt; (7, 5, &quot;S&quot;)&lt;/code&gt; …&lt;/p&gt;

&lt;p&gt;Then the only new behavior these examples would drive is &lt;strong&gt;composing commands&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So It turns out that there’s only one orthogonal example in this category. We might choose any of them, like the following one for instance:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(7, 4, &quot;E&quot;), &quot;frrbbl&quot; -&amp;gt; (10, 4, &quot;S&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This doesn’t mean that when we’re later doing TDD, we have to use only this example to drive the behavior. We can use more overlapping examples if we’re unsure on how to implement it and we need to use &lt;strong&gt;triangulation&lt;/strong&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we can consider the “oops” category which for us is &lt;strong&gt;unknown commands&lt;/strong&gt;. In this case, we need to find out how we’ll handle them and this might involve some conversations.&lt;/p&gt;

&lt;p&gt;Let’s say that we find out that we should ignore &lt;strong&gt;unknown commands&lt;/strong&gt;, then this might be an example:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(any_x, any_y, any_direction), &quot;*&quot; -&amp;gt; (any_x, any_y, any_direction)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Before finishing, I’d like to remark that it’s important to keep this technique as lightweight and informal as possible, writing the examples on a piece of paper or on a whiteboard, and never, ever, write them directly as tests (which I’ve also seen many times).&lt;/p&gt;

&lt;p&gt;There are two important reasons for this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Avoiding implementation details to leak into a process meant for thinking about the problem space.&lt;/li&gt;
  &lt;li&gt;Avoiding getting attached to the implementation of tests, which can create some inertia and push you to take implementation decisions without having explored the problem well.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;4-conclusion&quot;&gt;4. Conclusion.&lt;/h3&gt;

&lt;p&gt;Writing a list of examples before starting doing TDD is an often overlooked technique that can be very useful to reflect about a given problem. We also talked about how thinking in finding orthogonal examples can make your list of examples much more effective and saw some useful heuristics that might help you find them.&lt;/p&gt;

&lt;p&gt;Then we worked on a small example in tiny steps, compared different alternatives just to try to illustrate and make the technique more explicit and applied one of the heuristics.&lt;/p&gt;

&lt;p&gt;With practice, this technique becomes more and more a mental process. You’ll start doing it in your mind and find orthogonal examples faster. At the same time, you’ll also start losing awareness of the process&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nonetheless, writing a list of examples or other similar lightweight exploration techniques can still be very helpful for more complicated cases. This technique can also be very useful to think in a problem when you’re working on it with someone else (pairing, mob programming, etc.), because it enhances communication.&lt;/p&gt;

&lt;h3 id=&quot;5-acknowledgements&quot;&gt;5. Acknowledgements.&lt;/h3&gt;

&lt;p&gt;Many thanks to &lt;a href=&quot;https://twitter.com/alfredocasado?lang=en&quot;&gt;Alfredo Casado&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alvarobiz&quot;&gt;Álvaro Garcia&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/amisai&quot;&gt;Abel Cuenca&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/jaimeperera&quot;&gt;Jaime Perera&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/rojo_angel&quot;&gt;Ángel Rojo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran Reyes&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mjtordesillas&quot;&gt;Manuel Tordesillas&lt;/a&gt; for giving me great feedback to improve this post and for all the interesting conversations.&lt;/p&gt;

&lt;h3 id=&quot;6-references&quot;&gt;6. References.&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;Test-driven Development: By Example&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/18/complexity-dimensions-p1.html&quot;&gt;Complexity dimensions - FizzBuzz part I&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/19/complexity-dimensions-p2.html&quot;&gt;Complexity dimensions - FizzBuzz part II&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/20/complexity-dimensions-p3.html&quot;&gt;Complexity dimensions - FizzBuzz part III&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.wingman-sw.com/archives/677&quot;&gt;TDD Guided by ZOMBIES&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/jwgrenning/&quot;&gt;James Grenning&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://propertesting.com/&quot;&gt;PropEr Testing&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mononcqc?lang=en&quot;&gt;Fred Hebert&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/marick/Midje/wiki/Metaconstants&quot;&gt;Metaconstants&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/marick&quot;&gt;Brian Marick&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;7-footnotes&quot;&gt;7. Footnotes.&lt;/h3&gt;
&lt;p&gt;&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt;[1] This concept of &lt;strong&gt;orthogonal examples&lt;/strong&gt; is directly related to Mateu Adsuara’s &lt;strong&gt;dimensions of complexity&lt;/strong&gt; idea because each dimension of complexity can be driven using a different set of orthogonal examples. For a definition of dimensions of complexity, see footnote [4].&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt;[2] Another very useful heuristic is described in &lt;a href=&quot;https://www.linkedin.com/in/jwgrenning/&quot;&gt;James Grenning&lt;/a&gt;’s &lt;a href=&quot;http://blog.wingman-sw.com/archives/677&quot;&gt;TDD Guided by ZOMBIES post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt;[3] This is somehow related to &lt;a href=&quot;https://twitter.com/marick&quot;&gt;Brian Marick&lt;/a&gt;’s &lt;a href=&quot;https://github.com/marick/Midje/wiki/Metaconstants&quot;&gt;metaconstants&lt;/a&gt; which can be very useful to write tests in dynamic languages. They’re also hints about properties that might be helpful in &lt;a href=&quot;https://propertesting.com/book_foundations_of_property_based_testing.html&quot;&gt;property-based testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt;[4] &lt;strong&gt;Dimension of Complexity&lt;/strong&gt; is a term used by &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt; in a talk at Socrates Canarias 2016 to name an orthogonal functionality. In that talk he used dimensions of complexity to classify the examples in his tests list in different groups and help him choose the next test when doing TDD. He talked about it in these three posts: &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/18/complexity-dimensions-p1.html&quot;&gt;Complexity dimensions - FizzBuzz part I&lt;/a&gt;, &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/19/complexity-dimensions-p2.html&quot;&gt;Complexity dimensions - FizzBuzz part II&lt;/a&gt; and &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/20/complexity-dimensions-p3.html&quot;&gt;Complexity dimensions - FizzBuzz part III&lt;/a&gt;.
Other names for the same concept that I’ve heard are &lt;strong&gt;axes of change&lt;/strong&gt;, &lt;strong&gt;directions of change&lt;/strong&gt; or &lt;strong&gt;vectors of change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt;[5] Even though &lt;strong&gt;triangulation&lt;/strong&gt; is probably the most popular, there are two other strategies for implementing new functionality in TDD: &lt;strong&gt;obvious implementation&lt;/strong&gt; and &lt;strong&gt;fake it&lt;/strong&gt;. &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; in his &lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;Test-driven Development: By Example book&lt;/a&gt; describes the three techniques and says that he prefers to use &lt;strong&gt;obvious implementation&lt;/strong&gt; or &lt;strong&gt;fake it&lt;/strong&gt; most of the time, and only use &lt;strong&gt;triangulation&lt;/strong&gt; as a last resort when design gets complicated.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt;[6] This &lt;strong&gt;loss of awareness of the process&lt;/strong&gt; is the price of expertise according to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition&quot;&gt;Dreyfus model of skill acquisition&lt;/a&gt;.&lt;/p&gt;
</description>
          <pubDate>2018-03-20T17:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/03/examples-lists-in-tdd</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/03/examples-lists-in-tdd</guid>
        </item>
      
    
      
        <item>
          <title>Muchas gracias Luis</title>
          <description>&lt;p&gt;Luis lleva tiempo centrado en su nueva aventura, Codium, a la vez que colabora con nosotros puntualmente como anteriormente había hecho. Debido a la vorágine del presente, aún no habíamos podido sentarnos a contarlo. Con este post nos gustaría hacerle un pequeño homenaje a Luis y agradecerle todo lo que ha aportado a Codesai hasta ahora, y desearle mucha suerte con Codium. Nuestra colaboración sigue adelante.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fran&lt;/strong&gt;: El pragmatismo y la capacidad de evaluar rápidamente costes y beneficios de una decisión son características que junto con su honestidad hacen de Luis un profesional que querrías tener en tu proyecto. Seguiremos aprovechando todo esto de él, aunque ahora le toque dar más foco su proyecto junto con Jordi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alfredo&lt;/strong&gt;: Gracias Luis por todo lo aportado a Codesai durante este tiempo, tu visión y tu forma honesta y pragmática de expresarla siempre ha sido de gran valor para todos nosotros. Lo mejor de Luis es que, además de sus indudables conocimientos técnicos, tiene la capacidad de entender el negocio y enfocar el desarrollo de software siempre desde la perspectiva de aportar valor a ese negocio. Esta combinación de características, capacidad técnica y enfoque en la aportación de valor, es en mi opinión la clave para ser un gran profesional en este sector. Suerte a ti y a jordi en vuestra aventura con Codium!.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dácil&lt;/strong&gt;: Gracias, Luis, por sumar tanto al equipo en todo este tiempo, por ser siempre tan sincero, tan directo, por tu sempiterna predisposición. Para nosotros es ilusionante ver crecer tu proyecto y saber que existe un estrecho lazo que lo une a Codesai. Sé con certeza que seguirás sumando cada vez que lo necesitemos y viceversa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ronny&lt;/strong&gt;: Ha sido un auténtico placer compartir esta experiencia contigo Luis. Me has enseñado mucho, no he tenido oportunidad aún de compartir un proyecto contigo, pero en cada discusión me has aportado. Principalmente destaco tu pragmatismo y tu forma de exponer. Para mí ha sido un referente no solo en el apartado técnico sino que también en la comunicación. Me alegra saber que la naturaleza de nuestros proyectos está tan ligada que seguiré teniendo la oportunidad de aprender de ti. De hecho, no descartes que Miguel y yo te volvamos a necesitar un miércoles a las 8 de la tarde para que nos ayudes con el Doctrine. Me hace muy feliz que proyectos como Codium salgan adelante, tenéis mucho que aportar! Mucha suerte!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Miguel&lt;/strong&gt;: Fue con Luis con quien compartí mi primer proyecto de desarrollo asumiendo responsabilidades en Codesai. Siempre agradeceré la confianza que depositó en mí y las numerosas enseñanzas que me quedan desde entonces. La mentalidad Lean, el obtener feedback lo antes posible, en definitiva, aportar valor en su máximo exponente. Gracias por tus sabios consejos y tu capacidad de dar feedback de forma tan constructiva. Siempre hemos tenido la fortuna de contar con tu opinión y consejos en Codesai y quería expresarte mi gratitud por ello. Sé que en el futuro nuestros lazos seguirán ligados y que estamos aquí para lo que necesites. Gracias por tanto!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manuel Tordesillas&lt;/strong&gt;: Aunque no haya tenido el placer de desarrollar codo a codo con Luis, he tenido la gran oportunidad de aprender muchísimo de él tanto en el apartado profesional como en el personal. Su pragmatismo, su capacidad de síntesis y su deseo de aportar valor constantemente le convierten en un gran profesional y en un ejemplo para todos nosotros. Nuestros caminos seguirán cruzándose, mucha suerte con Codium!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dani&lt;/strong&gt;: Siempre me ha alucinado la capacidad de Luis para dar con el punto necesario y volver a enfocar la discusión justo cuando ésta empieza a dar vueltas. Muy preocupado por la productividad, cuando estoy con él siento que no va a pasar un minuto bien aprovechado. A destacar su pragmatismo y una forma muy objetiva de enfocar las cosas, estimo increíblemente valiosa su participación en cualquier debate.
Desearía haber podido trabajar más juntos porque también estoy al tanto de su calidad como desarrollador y no puedo sino considerarlo un gran profesional lleno de aptitudes, pero sé que seguiremos teniendo oportunidades para hacerlo sin problema colaborando con Codium. También seguiremos coincidiendo en la comunidad, mucha suerte y muchas gracias por todo Luis!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manuel Rivero&lt;/strong&gt;: He tenido la suerte de trabajar con Luis en muchas formaciones. Creo que es una persona fiable, sincera, respetuosa, directa y flexible, que sabe tanto dar como recibir feedback. He aprendido muchísimo de él. Creo que su forma de pensar y sus contribuciones han sido valiosísimas para Codesai y es un gran formador. Le tengo mucho aprecio. Seguiremos colaborando juntos en el futuro. ¡Mucha suerte con Codium y muchas gracias por todo Luis!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antonio&lt;/strong&gt;: Llevo año y medio en Codesai y durante este tiempo, los momentos de grandes conversaciones y debates han sido frecuentes y en esos casos, la opinión de Luis siempre era valiosa, mesurada y objetiva.
Y su trabajo con la comunidad está siendo una fuente de inspiración, ahora que estoy metiendo mucha energía en Agile Asturias; tanto por los repositorios de katas que tiene publicados, auténticas maravillas, como las propuestas de temas en el grupo de Murcia. Gracias!&lt;/p&gt;
</description>
          <pubDate>2018-03-12T07:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/03/muchas-gracias-luis</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/03/muchas-gracias-luis</guid>
        </item>
      
    
      
        <item>
          <title>Kata: Generating bingo cards with clojure.spec, clojure/test.check, RDD and TDD</title>
          <description>&lt;p&gt;&lt;a href=&quot;https://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Developers Barcelona&lt;/a&gt; has been running for several years now. Since we’re not many yet, we usually do &lt;a href=&quot;https://en.wikipedia.org/wiki/Mob_programming&quot;&gt;mob programming&lt;/a&gt; sessions as part of what we call “&lt;strong&gt;sagas&lt;/strong&gt;”. For each &lt;strong&gt;saga&lt;/strong&gt;, we choose an exercise or kata and solve it during the first one or two sessions. After that, we start imagining variations on the exercise using different Clojure/ClojureScript libraries or technologies we feel like exploring and develop those variations in following sessions. Once we feel we can’t imagine more interesting variations or we get tired of a given problem, we choose a different problem to start a new &lt;strong&gt;saga&lt;/strong&gt;. You should try doing &lt;strong&gt;sagas&lt;/strong&gt;, they are a lot of fun!
&lt;br /&gt;&lt;br /&gt;
Recently we’ve been working on the &lt;a href=&quot;https://agilekatas.co.uk/katas/Bingo-Kata&quot;&gt;Bingo Kata&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-initial-implementation&quot;&gt;The initial implementation&lt;/h3&gt;
&lt;p&gt;These were the tests we wrote to check the randomly generated bingo cards:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/71fead3e9ae26c034592d26eb4543eea.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and the code we initially wrote to generate them was something like (we didn’t save the original one):
&lt;script src=&quot;https://gist.github.com/trikitrok/b54cca91db243faec1e93dc9d25d2530.js&quot;&gt;&lt;/script&gt;
As you can see the tests are not concerned with which specific numeric values are included on each column of the bingo card. They are just checking that they follow the specification of a bingo card. This makes them very suitable for property-based testing.&lt;/p&gt;

&lt;h3 id=&quot;introducing-clojurespec&quot;&gt;Introducing clojure.spec&lt;/h3&gt;
&lt;p&gt;In the following session of &lt;strong&gt;the Bingo saga&lt;/strong&gt;, I suggested creating the bingo cards using &lt;a href=&quot;https://clojure.org/about/spec&quot;&gt;clojure.spec&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;&lt;strong&gt;spec&lt;/strong&gt;&lt;/em&gt; is a Clojure library to describe the structure of data and functions. Specs can be used to validate data, conform (destructure) data, explain invalid data, generate examples that conform to the specs, and automatically use generative testing to test functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a brief introduction to this wonderful library see &lt;a href=&quot;https://twitter.com/plexus&quot;&gt;Arne Brasseur&lt;/a&gt;’s &lt;a href=&quot;https://www.youtube.com/watch?v=-MeOPF94LhI&quot;&gt;Introduction to clojure.spec talk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’d used &lt;em&gt;clojure.spec&lt;/em&gt; at work before. At my current client &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;Green Power Monitor&lt;/a&gt;, we’ve been using it for a while to validate the shape (and in some cases types) of data flowing through some important public functions of some key name spaces. We started using pre and post-conditions for that validation (see Fogus’ &lt;a href=&quot;http://blog.fogus.me/2009/12/21/clojures-pre-and-post/&quot;&gt;Clojure’s :pre and :post&lt;/a&gt; to know more), and from there, it felt as a natural step to start using &lt;em&gt;clojure.spec&lt;/em&gt; to write some of them.
&lt;br /&gt;&lt;br /&gt;
Another common use of &lt;em&gt;clojure.spec&lt;/em&gt; specs is to generate random data conforming to the spec to be used for &lt;a href=&quot;https://hypothesis.works/articles/what-is-property-based-testing/&quot;&gt;property-based testing&lt;/a&gt;.
&lt;br /&gt;&lt;br /&gt;
In the Bingo kata case, I thought that we might use this ability of randomly generating data conforming to the spec in production code. This meant that instead of writing code to randomly generating bingo cards and then testing that the results were as expected, we might describe the bingo cards using &lt;em&gt;clojure.spec&lt;/em&gt; and then took advantage of that specification to randomly generate bingo cards using &lt;a href=&quot;https://github.com/clojure/test.check&quot;&gt;clojure.test.check&lt;/a&gt;’s &lt;a href=&quot;https://clojure.github.io/test.check/clojure.test.check.generators.html#var-generate&quot;&gt;generate function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So with this idea in our heads, we started creating a spec for bingo columns on the REPL bit by bit (for the sake of brevity what you can see here is the final form of the spec):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/b5f3c1fad97c87486de040e02a5f81c1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;then we discovered &lt;a href=&quot;https://clojuredocs.org/clojure.spec.alpha/coll-of&quot;&gt;clojure.spec’s coll-of&lt;/a&gt; function which allowed us to simplify the spec a bit:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a56215018d6d3e8568ae176daaba6cc3.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;generating-bingo-cards&quot;&gt;Generating bingo cards&lt;/h3&gt;

&lt;p&gt;Once we thought we had it, we tried to use the column spec to generate columns with &lt;em&gt;clojure.test.check&lt;/em&gt;’s &lt;em&gt;generate function&lt;/em&gt;, but we got the following error:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;ExceptionInfo Couldn’t satisfy such-that predicate after 100 tries&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course we were trying to find a needle in a haystack…&lt;/p&gt;

&lt;p&gt;After some trial and error on the REPL and reading &lt;a href=&quot;https://clojure.org/guides/spec&quot;&gt;the clojure.spec guide&lt;/a&gt;, we found the &lt;a href=&quot;https://clojuredocs.org/clojure.spec.alpha/int-in&quot;&gt;clojure.spec’s int-in&lt;/a&gt; function and we finally managed to generate the bingo columns:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/70f5ed78fd48d001836382ec91db289b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then we used the spec code from the REPL to write the bingo cards spec:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d076c0bc5d68b1fdcbea4a99cd147b63.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;in which we wrote the &lt;em&gt;create-column-spec&lt;/em&gt; factory function that creates column specs to remove duplication between the specs of different columns.&lt;/p&gt;

&lt;p&gt;With this in place the bingo cards could be created in a line of code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/54cce3ba289ac15a63508e7cf83054ad.js&quot;&gt;&lt;/script&gt;

&lt;h3 id=&quot;introducing-property-based-testing&quot;&gt;Introducing property-based testing&lt;/h3&gt;
&lt;blockquote&gt;
  &lt;p&gt;Property-based tests make statements about the output of your code based on the input, and these statements are verified for many different possible inputs. 
Jessica Kerr (&lt;a href=&quot;http://blog.jessitron.com/2013/04/property-based-testing-what-is-it.html&quot;&gt;Property-based testing: what is it?&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having the specs it was very easy to change our bingo card test to use &lt;em&gt;property-based testing&lt;/em&gt; instead of &lt;em&gt;example-based testing&lt;/em&gt; just by using the &lt;em&gt;generator&lt;/em&gt; created by &lt;em&gt;clojure.spec&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/79e55460d3cd3e6e305c463324fef415.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;See in the code that we’re reusing the &lt;em&gt;check-column&lt;/em&gt; function we wrote for the &lt;em&gt;example-based tests&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This change was so easy because of:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;clojure.spec&lt;/em&gt; can produce a generator for &lt;em&gt;clojure/test.check&lt;/em&gt; from a given spec.&lt;/li&gt;
  &lt;li&gt;The initial example tests, as I mentioned before, were already checking the properties of a valid bingo card. This means that they weren’t concerned with which specific numeric values were included on each column of the bingo card, but instead, they were just checking that the cards followed the rules for a bingo card to be valid.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;going-fast-with-repl-driven-development-rdd&quot;&gt;Going fast with REPL driven development (RDD)&lt;/h3&gt;
&lt;p&gt;The next user story of the kata required us to check a bingo card to see if its player has won. We thought this might be easy to implement because we only needed to check that the numbers in the card where contained by the set of called numbers, so instead of doing TDD, we &lt;del&gt;played a bit on the REPL&lt;/del&gt; did REPL-driven development (RDD):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d26e5826959302bf6eb91d8c211bc0c0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Once we had the implementation working, we copied it from the REPL into its corresponding name space 
&lt;br /&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/915e7a3b54ae606d3c6bf23c20b6c64a.js&quot;&gt;&lt;/script&gt;
and wrote the quicker but ephemeral REPL tests as “permanent” unit tests:
&lt;br /&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/trikitrok/054f77643d9aa3d5e9c1bcea47fa4a99.js&quot;&gt;&lt;/script&gt;
In this case RDD allowed us to go faster than TDD, because RDD’s feedback cycle is much faster. Once the implementation is working on the REPL, you can choose which REPL tests you want to keep as unit tests.&lt;/p&gt;

&lt;p&gt;Some times I use only RDD like in this case, other times I use a mix of TDD and RDD following this cycle:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Write a failing test (using examples that a bit more complicated than the typical ones you use when doing only TDD).&lt;/li&gt;
  &lt;li&gt;Explore and triangulate on the REPL until I made the test pass with some ugly but complete solution.&lt;/li&gt;
  &lt;li&gt;Refactor the code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Other times I just use TDD.&lt;/p&gt;

&lt;p&gt;I think what I use depends a lot on how easy I feel the implementation might be.&lt;/p&gt;

&lt;h3 id=&quot;last-details&quot;&gt;Last details&lt;/h3&gt;
&lt;p&gt;The last user story required us to create a bingo caller that randomly calls out Bingo numbers. To develop this story, we used TDD and an &lt;a href=&quot;https://clojure.org/reference/atoms&quot;&gt;atom&lt;/a&gt; to keep the not-yet-called numbers. These were our tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ddcddaaf2f21912c7dff475908746a64.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and this was the resulting code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/de9d634f4d6864f7bfde86768324ace9.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And it was done! See &lt;a href=&quot;https://github.com/trikitrok/bingo-kata-clojure/commits/master&quot;&gt;all the commits&lt;/a&gt; here if you want to follow the process (many intermediate steps happened on the REPL). You can find all &lt;a href=&quot;https://github.com/trikitrok/bingo-kata-clojure&quot;&gt;the code on GitHub&lt;/a&gt;.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;This experiment was a lot of fun because we got to play with both &lt;em&gt;clojure.spec&lt;/em&gt; and &lt;em&gt;clojure/test.check&lt;/em&gt;, and we learned a lot. While explaining what we did, I talked a bit about &lt;em&gt;property-based testing&lt;/em&gt; and how I use &lt;em&gt;REPL-driven development&lt;/em&gt;.
&lt;br /&gt;&lt;br /&gt;
Thanks again to all my colleagues in &lt;a href=&quot;https://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Developers Barcelona&lt;/a&gt;!&lt;/p&gt;
</description>
          <pubDate>2018-03-12T07:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/03/kata-generating-bingo-cards</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/03/kata-generating-bingo-cards</guid>
        </item>
      
    
      
        <item>
          <title>Muchas gracias Carlos</title>
          <description>&lt;p&gt;Queríamos anunciaros que Carlos deja Codesai para emprender un nuevo proyecto personal. Un gran compañero se va y queremos agradecerle toda lo que ha hecho por el equipo. Ha sido fundamental para que Codesai llegase a ser lo que es hoy. Han sido unos años muy intensos y fructíferos en los que hemos aprendido mucho los unos de los otros.&lt;/p&gt;

&lt;p&gt;Carlos, nos alegramos mucho viendo la ilusión con la que emprendes tu nuevo proyecto y queremos desearte lo mejor. ¡Muchísima suerte!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fran:&lt;/strong&gt; No podría hablar de mi camino profesional sin nombrar a  Carlos. Trabajador incansable con el que he podido colaborar durante bastante tiempo de manera directa. Su visión y la capacidad de pensar diferente junto a su habilidad para establecer relaciones han hecho que pudiera aprender de él cosas que es muy difícil encontrar en otros desarrolladores de software. Espero poder seguir aprendiendo de él aunque nuestros caminos se bifurquen un poco. Muchas gracias por tu energía en Codesai y aporte a la comunidad. Tu nuevo camino seguro que deja huella e inspiración para otros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alfredo:&lt;/strong&gt; Fue ya a finales de 2014 cuando gracias a Carlos aparecimos un buen día en Las Palmas cuatro locos: Carlos, Fran, Modesto y yo ilusionados apunto de empezar un nuevo proyecto, que al final resultó ser no sólo un proyecto más sino el germen de lo que hoy es Codesai. Lo mejor de Carlos es la iniciativa que ha tenido siempre para movilizar a la gente y embarcarlos en sus aventuras, ninguno de los que hoy formamos Codesai estaríamos aquí hoy si no fuera por Carlos. ¡Suerte en tus nuevas iniciativas!, y que esto no suene a despedida porque seguro que vamos a seguir colaborando en muchos proyectos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dácil:&lt;/strong&gt; No necesitarás suerte porque eres un auténtico hard-worker de voluntad indomable… Cada nuevo comienzo es una oportunidad para mejorar, para crecer, para aprender. Traza tu propia senda tantas veces como haga falta… Vamosss, darling!! ;-)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ronny:&lt;/strong&gt; No sabría definir mis sentimientos, por un lado estoy triste, se va de Codesai un mentor, compañero y gran amigo. Contigo empezó todo para mí, una cena cambió mi vida radicalmente para convertirme en el primer aprendiz de un proyecto apasionante. Has marcado mucho la persona y el profesional que soy hoy. Te agradezco todo lo que has hecho por mí. Por otro lado, siento alegría. Porque como dije antes, por encima de un compañero eres un gran amigo. Soy consciente de la ilusión con la que afrontas tus nuevos proyectos y espero que te vaya fenomenal. Gracias por emprender y gracias por plantar los cimientos para que algo tan bonito como Codesai pueda seguir su rumbo. ¡Muchas gracias por todo y te deseo muchos éxitos con tus próximas aventuras!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Miguel:&lt;/strong&gt; Es difícil enumerar las veces que Carlos siempre estaba dispuesto a echarte una mano. Siempre he tratado con él como un buen amigo además de un gran compañero de trabajo, siempre dispuesto y colaborador. Desde que te conocí me has abierto muchas puertas y facilitado mi formación y desarrollo como profesional e individuo, nunca estaré lo suficientemente agradecido por ello. Gracias por ser el punta de lanza en la creación de Codesai, permitir que estemos donde estamos hoy y de traer a la gente que hoy nos conforma. Solo me queda desearte mucha suerte en tus nuevos proyectos y que pongas de toda tu pasión y buen hacer para lograr tus propósitos. ¡Un fuerte abrazo y mucho ánimo de ahora en adelante y hasta que nos volvamos a cruzar!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manuel Tordesillas:&lt;/strong&gt; Si pienso en Carlos, lo primero que me viene a la cabeza es su imparable necesidad de generar un impacto positivo en su entorno. Hace aproximadamente un año Carlos me ofreció entrar en Codesai. No lo dudé y ha resultado ser una de las mejores decisiones que he tomado en mi vida. Un año después sigo aprendiendo, creciendo como profesional, como persona  y descubriendo cosas nuevas cada día. Estoy seguro que en su nuevo camino seguirá luchando su cruzada por mejorar el mundo y generando oportunidades allá donde vaya. Espero tener algún día el mismo impacto positivo en la vida de otros como él ha tenido en la mía.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dani:&lt;/strong&gt; Una de las decisiones que te cambian la vida fue la que yo tomé lanzándome sin pensarlo dos veces a un curso de TDD impartido por Carlos en la isla de al lado hace ya casi 3 años. El yo de aquél entonces se estaba aventurando en un mundo de programación de videojuegos porque era la única faceta chula que le veía al mundo del software, mientras hacía alguna que otra kata de vez en cuando en la comunidad.
La inyección de pasión y conocimiento que recibí en ese curso de la mano de Carlos desencadenó un cambio progresivo en mí que se hizo más fuerte según más le iba conociendo e iba intercambiando opiniones con él. Lo que al principio empezó como un nuevo y maravilloso camino en el mundo del desarrollo se convirtió en una nueva forma de pensar y ver el mundo, en otro estilo de comunicación basado en la observación y la escucha.
Valoro enormemente lo que me has aportado a nivel de persona, lo que me has hecho evolucionar tanto de forma consciente como inconsciente, y no puedo sino esperar impacientemente por el próximo día en el que compartamos una buena charla.
Mucha suerte con todo Carlos, nos vemos!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manuel Rivero:&lt;/strong&gt; Carlos, muchísimas gracias por introducirme en un grupo humano tan chulo como Codesai. Espero que te vaya muy bien en tu nuevo proyecto. ¡Muchísima suerte!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antonio:&lt;/strong&gt; Carlos siempre te agradeceré ser la primera persona que me hizo ver que era factible mi sueño de volver a Asturias después de 12 años fuera de mi tierra. Me has aportado muchas cosas, pero la que más ha cambiado mi vida es empezar a ver el trabajo como un medio para tener una vida mejor. Comprender que uno tiene control sobre cada una de las acciones que hace y eso incluye dónde y cómo se trabaja. ¡Muchísima suerte en tus nuevos proyectos!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Luis:&lt;/strong&gt; La verdad es que hacia Carlos sólo puedo tener palabras de agradecimiento, pues con él me introduje en TDD hace casi 10 años. Años más tarde me abrió la puerta a la formación con mi primer curso en Ironhack y posteriormente acompañándole a impartir cursos de TDD. En el plano personal admiro su altruismo y la forma que tiene de brindar oportunidades a los demás.
Y creo que esa es la clave de tu nueva aventura: seguir ayudando a los demás a trabajar en proyectos chulos, desde donde quieran trabajar y con una mentorización dedicada. Un fuerte abrazo y seguimos en contacto, pues nuestros caminos se cruzarán muchas veces :)&lt;/p&gt;
</description>
          <pubDate>2018-03-01T22:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2018/03/muchas-gracias-carlos</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2018/03/muchas-gracias-carlos</guid>
        </item>
      
    
      
        <item>
          <title>Charla Valores y principios en el diseño del software en CAS17</title>
          <description>&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-sm-8&quot;&gt;
    &lt;img src=&quot;/assets/fizzBuzzKataRuleEngine.png&quot; alt=&quot;detalle slide charla fran cas17&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Tras la charla que dimos &lt;a href=&quot;https://twitter.com/alfredocasado&quot;&gt;Alfredo&lt;/a&gt; y yo en el &lt;a href=&quot;/2016/07/estuvimos-en-aos2k16&quot;&gt;AOS en Santiago de compostela de 2016&lt;/a&gt; y el trabajo que hemos hecho en Codesai (en &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;[1]&lt;/a&gt;, &lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;[2]&lt;/a&gt; y &lt;a href=&quot;/2017/08/cop-builders-and-fluid-interfaces&quot;&gt;[3]&lt;/a&gt;), especialmente &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;, sobre el concepto de &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;Connascence&lt;/a&gt;, me apetecía explorar otra perspectiva sobre los elementos del diseño del software en un ámbito más amplio y por tanto menos preciso. Uno de los beneficios de connascence es que elimina cierta ambiguedad que algunos principios (por ejemplo SOLID) pueden introducir al intentar comprenderlos pero por contra el conjunto de elementos que puede explicar es limitado. El objetivo final era añadir más herramientas para apreciar y escribir mejor software.&lt;/p&gt;

&lt;p&gt;En la &lt;a href=&quot;http://cas2017.agile-spain.org/&quot;&gt;CAS del 2017 de Sevilla&lt;/a&gt; tuve la suerte de que mi charla fuera aceptada, lo que me daba la tensión suficiente para trabajar en el tema. No hay nada como buscar la excusa de ofrecer una charla para explorar más en profundidad un tema.&lt;/p&gt;

&lt;p&gt;El libro de Kent Beck &lt;a href=&quot;https://www.goodreads.com/book/show/781559.Implementation_Patterns&quot;&gt;Implementation patterns&lt;/a&gt; (que había ojeado hace tiempo) ofrecía el espacio idóneo. La charla trata sobre como los principios y valores pueden ser aplicados en el diseño del software. El conjunto de valores (&lt;em&gt;Communication&lt;/em&gt;, &lt;em&gt;Simplicity&lt;/em&gt;, &lt;em&gt;Flexibility&lt;/em&gt;) y principios (&lt;em&gt;Local consequences&lt;/em&gt;, &lt;em&gt;Minimize Repetition&lt;/em&gt;, &lt;em&gt;Logic and Data Together&lt;/em&gt;, &lt;em&gt;Declarative Expression&lt;/em&gt;, &lt;em&gt;Symmetry&lt;/em&gt;, &lt;em&gt;Rate of Change&lt;/em&gt;) que son explorados en Implementation patterns son la base de la charla que acompaño de algunos ejemplos.&lt;/p&gt;

&lt;p&gt;En el transcurso de la preparación de la charla tuve la oportunidad de interactuar con algunas personas reconocidas en la comunidad como &lt;a href=&quot;https://twitter.com/natpryce&quot;&gt;Nat Pryce&lt;/a&gt; y el mismo &lt;a href=&quot;https://twitter.com/kentbeck&quot;&gt;Kent Beck&lt;/a&gt; (vean estos hilos en Twitter: &lt;a href=&quot;https://twitter.com/fran_reyes/status/916283991791210497&quot;&gt;[1]&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/fran_reyes/status/926131805555699712&quot;&gt;[2]&lt;/a&gt;), que amablemente respondieron a algunas de mis dudas y enriquecieron el contenido.&lt;/p&gt;

&lt;p&gt;Mi sensación al dar la charla en la CAS fue bastante agridulce. Por un lado el contenido parece que gustó pero por otro lado mis habilidades como ponente aún tienen que mejorar bastante. La esperanza de que la práctica deliberada vaya mejorando este aspecto me consuela.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-sm-8&quot;&gt;
    &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/fran_reyes?ref_src=twsrc%5Etfw&quot;&gt;@fran_reyes&lt;/a&gt; genial la charla... Muy instructiva, cada slide es oro :) 100% de acuerdo con todo &lt;a href=&quot;https://twitter.com/confagilespain?ref_src=twsrc%5Etfw&quot;&gt;@confagilespain&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/CAS2017?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#CAS2017&lt;/a&gt;&lt;/p&gt;&amp;mdash; Eduardo Ferro Aldama (@eferro) &lt;a href=&quot;https://twitter.com/eferro/status/928593531505176576?ref_src=twsrc%5Etfw&quot;&gt;November 9, 2017&lt;/a&gt;&lt;/blockquote&gt;
    &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
  &lt;/div&gt;


  &lt;div class=&quot;col-sm-2&quot;&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Este es el vídeo de la charla&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;sXLCBcELu5Y&quot;&gt;
    &lt;div data-id=&quot;sXLCBcELu5Y&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/sXLCBcELu5Y/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;y estas son &lt;a href=&quot;http://buildingthepath.com/talk-cas-2017/&quot;&gt;las slides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para terminar quiero dar las gracias a &lt;a href=&quot;https://www.autentia.com/&quot;&gt;Autentia&lt;/a&gt; por la grabación de la charla, a la organización de la CAS por esforzarse al máximo para que estuvieramos como en casa y a los asistentes por hacer del evento algo memorable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/cas_fran_2017.jpg&quot; alt=&quot;detalle slide charla fran cas17&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2017-12-29T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/charla-valores-y-principios-cas17</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/charla-valores-y-principios-cas17</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Cetelem</title>
          <description>&lt;p&gt;Hace unos meses &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;yo&lt;/a&gt; hicimos un curso de TDD en &lt;a href=&quot;https://www.cetelem.es/&quot;&gt;Cetelem&lt;/a&gt;. Para mi fue una gran experiencia porque los asistentes estaban muy motivados. Este fue el primer curso que hacía con Luis, y me gustó muchísimo trabajar con él. Me encantó el ritmo que Luis le da al curso, su contenido eminentemente práctico y como la teoría se mezcla con la práctica de un modo muy fluido.&lt;/p&gt;

&lt;p&gt;En cuanto al contenido, sustituimos la &lt;a href=&quot;http://simcap.github.io/coffeemachine/&quot;&gt;Coffe Machine kata&lt;/a&gt; por la &lt;a href=&quot;http://matteo.vaccari.name/blog/archives/154&quot;&gt;Birthday Greetings kata&lt;/a&gt; para introducir los dobles de prueba de forma más gradual.&lt;/p&gt;

&lt;p&gt;Muchísimas gracias a Cetelem por confiar en nosotros y a todos los asistentes por sus ganas de aprender.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/cetelem_mascota.jpg&quot; alt=&quot;Mascota Cetelem&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;ul&gt;
    &lt;li&gt;Gráfico TDD de &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software&lt;/a&gt; por Nat Pryce and Steve Freeman.&lt;/li&gt;
    &lt;li&gt;Imagen de &lt;a href=&quot;https://www.flickr.com/photos/cetelemspain/&quot;&gt;Flickr de Cetelem España&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
</description>
          <pubDate>2017-12-26T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/tdd-en-cetelem</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/tdd-en-cetelem</guid>
        </item>
      
    
      
        <item>
          <title>Charla Discusiones y decisiones: herramientas para la efectividad en CAS17</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/cas2017-charlaantonio1.jpg&quot; alt=&quot;charla antonio cas17 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hace un mes más o menos tuve el placer de dar una charla titulada “Discusiones y decisiones: herramientas para la efectividad” en la &lt;a href=&quot;https://cas2017.agile-spain.org/&quot;&gt;CAS (Conferencia Agile Spain) de este año 2017 que tuvo lugar en Sevilla&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La charla trataba de cómo conseguir que las múltiples reuniones que seguramente tienes al día sean más efectivas. Si te tienes que llevar unas ideas clave de mi charla serían éstas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Que una reunión es como un juego, que tiene una reglas y un tiempo que todo el mundo se ha propuesto cumplir.&lt;/li&gt;
  &lt;li&gt;Que este juego se divide en tres partes, la apertura en la que prima el pensamiento divergente donde no hay casi límites a las ideas, una intermedia de exploración y búsqueda de conexiones y un cierre que busca la convergencia en un conjunto de ideas que nos sirvan para dar los siguientes pasos.&lt;/li&gt;
  &lt;li&gt;Y que en todo momento hay que trabajar con algo tangible: una pizarra, postits, papeles, que nos permita a todos ver lo que estamos construyendo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/cas2017-charlaantonio3.jpg&quot; alt=&quot;charla antonio cas17 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hacía ya casi dos años que quería profundizar en este tema y por eso agradecí tanto a la organización de la CAS que aceptase esta charla.
Tengo una especial sensibilidad con la calidad de las reuniones que hago, sobre todo para que todo el que participe se sienta a gusto y lo pueda hacer sin sentirse coaccionado.
Esto al principio puede parecer que ocurre porque las personas somos mal educadas, pero investigando me di cuenta que muchas veces se debe a que se confunde la parte exploratoria o divergente, dónde caben las ideas locas que puedan llevar a otras más realistas, con la parte más crítica o convergente, dónde sí que hay que mirar las posibilidades reales de cada opción.
Si esta separación queda clara para todos, la discusión se desarrolla mucho más fluidamente.&lt;/p&gt;

&lt;p&gt;Mis sensaciones dando la charla fueron agridulces. Sentí que la charla necesitaba aún algo más de rodaje para poder tocar todos los temas que quería en tan poco tiempo. Quería incidir en la parte teórica que fundamenta toda reunión, porque la parte práctica estaba seguro que todos la tenemos más vista. Sin embargo, el feedback de algunas personas me hizo darme cuenta de que podía haberme parado un poco más en los ejemplos prácticos.&lt;/p&gt;

&lt;p&gt;Os comparto el video de la charla, espero que os resulte interesante. Quería aprovechar para una vez más darle muchísimas gracias a &lt;a href=&quot;https://www.youtube.com/user/AutentiaMedia&quot;&gt;Autentia&lt;/a&gt; por grabarla y por la labor brutal que está haciendo para difundir eventos técnicos.&lt;/p&gt;
&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;fDvr-fs01m8&quot;&gt;
    &lt;div data-id=&quot;fDvr-fs01m8&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/fDvr-fs01m8/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Y estas son las trasparencias:&lt;/p&gt;
&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;https://www.slideshare.net/slideshow/embed_code/key/BOAT3BXZ9jtPPR&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Para terminar muchísimas gracias a todos los asistentes y especialmente a todas las personas que hicieron posible la CAS de este año, un super evento que además hizo posible que conociese Sevilla.&lt;/p&gt;

&lt;p&gt;¡Nos vemos el próximo año en Alicante!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/cas2017-charlaantonio2.jpg&quot; alt=&quot;charla antonio cas17 2&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  Gracias a &lt;a href=&quot;https://twitter.com/DavidGomezR_&quot;&gt;David Gómez&lt;/a&gt; (&lt;a href=&quot;https://twitter.com/DavidGomezR_/status/928579650695069696&quot;&gt;1&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/DavidGomezR_/status/928578601393541121&quot;&gt;2&lt;/a&gt;) y a &lt;a href=&quot;https://twitter.com/Bea_Petazeta&quot;&gt;Beatriz Zarzo&lt;/a&gt; (&lt;a href=&quot;https://twitter.com/Bea_Petazeta/status/928584476057317376&quot;&gt;3&lt;/a&gt;) por dejarnos usar sus magníficas fotos.
&lt;/div&gt;
</description>
          <pubDate>2017-12-22T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/charla-discusiones-decisiones-cas17</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/charla-discusiones-decisiones-cas17</guid>
        </item>
      
    
      
        <item>
          <title>Tercer curso abierto de TDD del año en Barcelona</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/curso_tdd_bcn_3_kata.jpg&quot; alt=&quot;Kata en curso abierto de TDD de Noviembre 2017 en Barcelona&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En vista del éxito que habían tenido los dos cursos abiertos de TDD que habíamos hecho este año en Barcelona, nos decidimos a hacer un nuevo curso abierto en Noviembre. Los cursos en abierto me hacen especial ilusión porque fue en uno de estos cursos abiertos dado por &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;Carlos Blé&lt;/a&gt; en 2011 donde tuve la oportunidad de empezar a aprender sobre TDD.&lt;/p&gt;

&lt;p&gt;En principio ibamos a dar el curso &lt;a href=&quot;https://twitter.com/luisrovirosa?lang=en&quot;&gt;Luis&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;yo&lt;/a&gt;, pero, desgraciadamente, &lt;a href=&quot;http://garajeando.blogspot.com.es/2017/11/recovering.html&quot;&gt;sufrí el síndrome de Miller Fisher&lt;/a&gt;, y al final Luis tuvo que dar el curso en solitario.&lt;/p&gt;

&lt;p&gt;Asistieron ocho personas, de las cuales siete venían de la misma empresa, &lt;a href=&quot;http://www.systelabsw.com/&quot;&gt;Systelab&lt;/a&gt;. ¡Muchas gracias por confiar en nosotros y &lt;a href=&quot;https://en.wikipedia.org/wiki/Kudos&quot;&gt;kudos&lt;/a&gt; especiales para las personas que se pagaron el curso de su bolsillo!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_tdd_bcn_3_grupo.jpg&quot; alt=&quot;curso abierto de TDD deMayo 2017 en Barcelona&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El hecho de que casi todo el mundo viniese de la misma empresa hizo que no hubiera tanta variedad de lenguajes como en otros cursos en abierto: todos usaron Java. Las katas salieron de forma bastante fluida y el feedback que recibimos fue bastante bueno.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
&lt;div class=&quot;row&quot;&gt;    
  &lt;div class=&quot;col-md-offset-2 col-md-12 col-sm-12&quot;&gt;
   &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;es&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Finalizado el curso de TDD de &lt;a href=&quot;https://twitter.com/codesaidev?ref_src=twsrc%5Etfw&quot;&gt;@codesaidev&lt;/a&gt; facilitado por &lt;a href=&quot;https://twitter.com/luisrovirosa?ref_src=twsrc%5Etfw&quot;&gt;@luisrovirosa&lt;/a&gt; con la mochila de conocimientos a reventar y con enormes ganas de aplicar lo aprendido. Muuuuuuuuuyyyy recomendable!!!!!&lt;/p&gt;&amp;mdash; Fernando Monferrer (@Ferniter) &lt;a href=&quot;https://twitter.com/Ferniter/status/933029414333571072?ref_src=twsrc%5Etfw&quot;&gt;21 de noviembre de 2017&lt;/a&gt;
   &lt;/blockquote&gt;
   &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;2017 ha sido un año muy fructifero en lo que se refiere a los cursos en abierto de TDD en Barcelona. Hemos tenido la suerte de hacer tres cursos (ver posts sobre el &lt;a href=&quot;/2017/01/curso-abierto-tdd-en-bcn&quot;&gt;primero&lt;/a&gt; y el &lt;a href=&quot;/2017/06/segundo-curso-abierto-bcn&quot;&gt;segundo&lt;/a&gt;) y de conocer a un montón de gente estupenda. Muchísimas gracias a todos las personas que asistieron.&lt;/p&gt;

&lt;p&gt;Para finalizar quería dar las gracias a &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento&lt;/a&gt;, a &lt;a href=&quot;https://twitter.com/rojoangel&quot;&gt;Ángel Rojo&lt;/a&gt;, a &lt;a href=&quot;https://twitter.com/Ferniter&quot;&gt;Fernando Monferrer&lt;/a&gt; y a nuestra compañera &lt;a href=&quot;/2017/05/dacil-casanova-se-une-a-codesai&quot;&gt;Dácil&lt;/a&gt; por toda la ayuda que nos prestaron para que estos tres cursos llegaran a suceder.&lt;/p&gt;
</description>
          <pubDate>2017-12-15T11:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/tercer-curso-abierto-bcn</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/tercer-curso-abierto-bcn</guid>
        </item>
      
    
      
        <item>
          <title>We were at Lambda World 2017</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/lambda_world_main_hall.jpg&quot; alt=&quot;Lambda World Main Hall&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This last 26th and 27th of October I was a proud assistant of the &lt;a href=&quot;http://www.lambda.world/&quot;&gt;Lambda World&lt;/a&gt;. I gathered with some colleagues from Codesai (&lt;a href=&quot;http://www.twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt; and &lt;a href=&quot;http://www.twitter.com/adelatorrefoss&quot;&gt;Antonio de la Torre&lt;/a&gt;) and with some friends. It was also my first time on the event so I was kinda hyped.&lt;/p&gt;

&lt;p&gt;My main intention coming to the Conference was to be completely disrupted with this software programming paradigm. I’m a newbie when referring to functional programming and I’ve always wanted to learn it on my free time, but I’m usually stuck with topics related of what I want to improve on the clients I work on. So I thought this time it could be a great moment to finally awake that part of me that is waiting to start learning functional programming.&lt;/p&gt;

&lt;p&gt;The conference was comprised of three sections:
	- The first day there was an open space in the morning and several workshops in the afternoon.
The second day was a more conventional conference day full of talks.&lt;/p&gt;

&lt;p&gt;During the open space I enjoyed quite a lot a session by &lt;a href=&quot;https://twitter.com/runarorama&quot;&gt;Rúnar Bjarnason&lt;/a&gt;, it was an improvised crash course on Category Theory. I was quite amazed by the fact that he just opened a text editor and started writing every definition and identifying objects and arrows of every category.&lt;/p&gt;

&lt;p&gt;I also attended the workshop session: “Don’t fear the monad” by &lt;a href=&quot;https://twitter.com/lime_cl&quot;&gt;Antonio Leiva&lt;/a&gt;. I really liked his session, but it was quite uncomfortable having to follow the examples and doing the exercises on benches without a desk or table to place my laptop. The workshop was great, it covered a lot of topics which were greatly explained. The only downside of the workshop was that we had a really short time to do it ourselves (about only 5 minutes) and it was impossible (at least for me) to end the exercises without being familiar with Kotlin.&lt;/p&gt;

&lt;p&gt;On the second day I assisted to many talks. But I particularly enjoyed the ones facilitated by &lt;a href=&quot;https://twitter.com/hhariri&quot;&gt;Hadi Hariri&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/DanielaSfregola&quot;&gt;Daniela Sfregola&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;“&lt;a href=&quot;https://www.youtube.com/watch?v=a7QpoMj2uIA&quot;&gt;Kotlin 102&lt;/a&gt;” (I couldn’t find the link from the conference, so this one is from Devoxx Conference) was a great summary about many of the decisions that Jetbrains has made on designing Kotlin to be more functional-friendly and most importantly, remove unnecessary boilerplate to keep only the necessary tools. The talk was really funny and didactic. I got a deep insight of Kotlin and I can say I can’t wait to try it on any of my side projects.&lt;/p&gt;

&lt;p&gt;The second talk by Daniel Sfregola “&lt;a href=&quot;https://www.youtube.com/watch?v=MvQxNm5gn8g&quot;&gt;A Pragmatic Introduction to Category Theory&lt;/a&gt;” was a kind of Category Theory Developer Oriented talk. Basically it was a summary of each category, but removing all the abstraction, and explaining it straight from a code implementation. Although the talk itself wasn’t very revealing, in my case, it was a confirmation of everything I had learned during the conference about Category Theory and I felt a little proud of myself :)&lt;/p&gt;

&lt;p&gt;Also I assisted to the talk &lt;a href=&quot;https://www.youtube.com/watch?v=IL5XzaCMKpQ&quot;&gt;Functional Programming in Kotlin with Kategory&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/pacoworks&quot;&gt;Paco Estevez&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/raulraja&quot;&gt;Raúl Raja&lt;/a&gt; from &lt;a href=&quot;https://twitter.com/47deg&quot;&gt;47 Degrees&lt;/a&gt;.  It was an introductory talk about the library they have developed and every feature they have brought into Kotlin. I was mesmerized by how powerful and great it looked. The talk was really enjoyable and dynamic.
 And my last session was at the Keynote “&lt;a href=&quot;https://www.youtube.com/watch?v=l1FCXUi6Vlw&quot;&gt;Profunctor Optics: The Categorical Approach&lt;/a&gt;” by &lt;a href=&quot;https://twitter.com/bartoszmilewski&quot;&gt;Bartosz Milewski&lt;/a&gt;. Sadly I didn’t get a single clue of the talk. Too advanced for me. I hope I can watch it again in a year and understand it.&lt;/p&gt;

&lt;p&gt;Finally. I would like to thank the organization. The event was fantastic and the venue simply amazing. The only thing that I can think that might be improved are the workshops. I think benches are not a good place to program, but I understand that there was no other place in the venue that might have fixed that problem. That is what tradeoffs are about :D&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/lambda-world-organisers.jpg&quot; alt=&quot;Lambda World organisers&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And I would also like to give some feedback about the conference itself. In my opinion it would be really great having more topics apart from Category Theory, which was, no doubt the most discussed topic on the conference. For instance, I would have liked to have some more talks about dynamic functional languages.&lt;/p&gt;

&lt;p&gt;To conclude I’d like to thank everyone I have talked to during the conference. I had a great opportunity to meet new people and spend some time with my Codesai colleagues and friends. I hope I can make it again next year.&lt;/p&gt;

&lt;p&gt;I’m glad because I finally had the chance to come to this conference and immerse myself in this FP “world”.&lt;/p&gt;

&lt;p&gt;I got a new perspective on applying functional programming for my day-to-day work. I’m happy because I feel that a lot of new paths have suddenly opened in front of me and I love it. I will try to practice more with this paradigm and get a better understanding of it. I hope next year I can understand a 30% of what is told in the conference talks. But for a newbie, understanding a 10% I think it’s a good starting point.&lt;/p&gt;

&lt;p&gt;Thanks everybody for an amazing Lambda World 2017!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/lambda_world_friends.jpg&quot; alt=&quot;Lambda World Main Hall&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2017-12-04T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/we-were-at-lambda-world-2017</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/we-were-at-lambda-world-2017</guid>
        </item>
      
    
      
        <item>
          <title>We were at Merkle</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/comet-curso-tdd-4.jpg&quot; alt=&quot;Momento 2 curso TDD Merkle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Last October &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis Rovirosa&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/jordianguela&quot;&gt;Jordi Anguela&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;I&lt;/a&gt; had the pleasure to give three TDD trainings at &lt;a href=&quot;https://www.cometgc.com/#homepage&quot;&gt;Merkle&lt;/a&gt;’s impressive offices in Barcelona. Merkle is a consulting company distributed worldwide which is very committed to deliver not only value but also high quality software to their clients.&lt;/p&gt;

&lt;p&gt;We worked with three groups comprised of people from different teams. This mix was challenging but also rewarding because the members of each team brought with them different set of problems, skills and practices, which lead to interesting discussions and opportunities to learn. All in all, I think we managed to satisfy the expectations they had about our training.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/comet-curso-tdd-5.jpg&quot; alt=&quot;Momento 1 curso TDD Merkle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I delivered two of the trainings with Luis, and Jordi and Luis the other one. Every time it’s possible we try to give our trainings in pairs because we think it makes them much better. Being two we can devote more time to give feedback and help each person with their doubts while they are working through the katas. It also helps us monitor our audience better so that we can adapt our message to their needs.&lt;/p&gt;

&lt;p&gt;We loved working with such great people. We’d like to thank them all for the great time we had. We’d also like to specially thank &lt;a href=&quot;https://www.linkedin.com/in/nelsoncardenas/&quot;&gt;Nelson Cardenas&lt;/a&gt; for having contacted us to work with them. We’d love to continue collaborating with this great team in the future.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/comet-curso-tdd-3.jpg&quot; alt=&quot;asistentes al curso 1 de TDD en Merkle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/comet-curso-tdd-2.jpg&quot; alt=&quot;asistentes al curso 2 de TDD en Merkle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/comet-curso-tdd-1.jpg&quot; alt=&quot;asistentes al curso 3 de TDD en Merkle&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2017-12-02T16:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/12/we-were-at-merkle-comet</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/12/we-were-at-merkle-comet</guid>
        </item>
      
    
      
        <item>
          <title>Native/Browser SPA versions using ClojureScript and re-frame talk at SCBCN17</title>
          <description>&lt;p&gt;Last month I had the pleasure of giving a talk at the &lt;a href=&quot;http://scbcn.github.io/&quot;&gt;Software Craftsmanship Barcelona 2017 conference&lt;/a&gt; about what my colleague &lt;a href=&quot;https://twitter.com/zesc&quot;&gt;Francesc&lt;/a&gt; and I have been learning lately while working on the mobile and browser versions of a SPA using ClojureScript and &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;.
&lt;br /&gt;&lt;br /&gt; 
I talked mainly about &lt;b&gt;how re-frame’s effects and coeffects, re-frame’s subscriptions and modelling a UI as &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite-state_machine&quot;&gt;FSM&lt;/a&gt;s place you in a pit of success&lt;/b&gt;, i. e., a design that, &lt;a href=&quot;https://blog.codinghorror.com/falling-into-the-pit-of-success/&quot;&gt;according to Jeff Atwood&lt;/a&gt;, “&lt;i&gt;makes it easy to do the right things and annoying (but not impossible) to do the wrong things&lt;/i&gt;”.
&lt;br /&gt;&lt;br /&gt; 
It was my first talk in a big conference and I had some technical problems, so I was very nervous at the beginning. After a while I relaxed and felt better. In the end I received more questions than I expected and very nice feedback.
&lt;br /&gt;&lt;br /&gt; 
I’d like to thank Modesto for lending me his computer when mine crashed just before the talk and helping me relax.
&lt;br /&gt;&lt;br /&gt; 
This is the video of the talk, (thanks &lt;a href=&quot;https://www.youtube.com/user/AutentiaMedia&quot;&gt;Autentia&lt;/a&gt; for recording all the talks and for being so kind to me when I was having technical difficulties). I hope you’ll find it interesting:
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;p1fXJyomXNQ&quot;&gt;
    &lt;div data-id=&quot;p1fXJyomXNQ&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/p1fXJyomXNQ/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;and these are &lt;a href=&quot;https://docs.google.com/presentation/d/1Rha0DTEdDfq_uoek6ksju3vPnJkiyS3zBfAhFvsf5Fo/edit?usp=sharing&quot;&gt;the slides&lt;/a&gt; that I’ve improved after the talk using Modesto’s feedback (thanks!!): .
&lt;br /&gt;&lt;br /&gt; 
Thanks to Francesc and all the people in &lt;a href=&quot;https://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Developers Barcelona Group&lt;/a&gt;, &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;Green Power Monitor&lt;/a&gt; and &lt;a href=&quot;https://www.codesai.com/&quot;&gt;Codesai&lt;/a&gt; that contributed to improve the talk with their feedback. Also thanks to my colleague &lt;a href=&quot;https://twitter.com/adelatorrefoss&quot;&gt;Antonio&lt;/a&gt; for “persuading” me to give a talk in a conference.
&lt;br /&gt;&lt;br /&gt; 
Finally, I’d also like to thank &lt;a href=&quot;http://scbcn.github.io/&quot;&gt;Software Craftsmanship Barcelona 2017 conference&lt;/a&gt; organizers for giving me the opportunity to talk at such a great conference and for all the effort they put to make this conference better, edition after edition.&lt;/p&gt;
</description>
          <pubDate>2017-11-17T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/11/SPA-ClojureScript-re-frame-talk-SCBCN17</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/11/SPA-ClojureScript-re-frame-talk-SCBCN17</guid>
        </item>
      
    
      
        <item>
          <title>Software Craftsmanship Barcelona 2017</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/scbcn17-logo.jpeg&quot; alt=&quot;SCBCN17 Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Four weekends ago, a few colleagues from Codesai and I attended the &lt;a href=&quot;http://scbcn.github.io/&quot;&gt;Software Craftsmanship Barcelona 2017 conference&lt;/a&gt;. While some of them had already come in previous years, I was a first timer and my expectations were very high. I have heard very positive comments from attendees to previous editions. For the year I lived in Barcelona, I became a member of the community and tried to attend to all the katas every Monday, where information about the event leaked little by little. I was lucky to get them on the first day on sale.&lt;/p&gt;

&lt;p&gt;I would like to thank the organisers and the community, all this anticipation and nerves for getting the tickets were well worth it.&lt;/p&gt;

&lt;h2 id=&quot;talks&quot;&gt;Talks&lt;/h2&gt;

&lt;p&gt;It was hard to choose which talks to attend to but thanks to autentia, we can watch all the talks over and over again. From every talk I attended to I took home at least one important learning pill.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=p1fXJyomXNQ&quot;&gt;Native and browser SPA versions using re-frame, ClojureScript and ReactNative&lt;/a&gt; &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;Manuel Rivero&lt;/a&gt;
On this talk, my colleague and mentor Manuel shared his learnings from one of his projects using ClojureScript and re-frame. I found the concept of effects and coeffects very interesting and I am tempted to get over the parentheses (or “elegant weapons for a more civilized age” as he prefers to call them) and start learning Clojure.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6FDxbCzh2sI&quot;&gt;Simplicidad (para desarrolladores)&lt;/a&gt; &lt;a href=&quot;https://twitter.com/eferro&quot;&gt;Edu Ferro&lt;/a&gt;
Edu made a very convincing case for the need of developers to put their feet on the ground and design solutions with simplicity in mind. I really liked the concept that he introduced for introducing new features in our systems:  refactor the code before integrating that feature for it to fit as if it was designed with the rest of the system from the get go.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=BtxhAD3gcPI&quot;&gt;Slow Life (Como montárselo bien como programador)&lt;/a&gt; &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis Rovirosa&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/jordianguela&quot;&gt;Jordi Anguela&lt;/a&gt;
Luis and Jordi tried to make us reflect whether we feel we are doing well or not as developers in both our professional and personal lives. I found the talk very insightful, with tips and tricks to prioritize our objectives and to reach the point where we want to be. I felt reflected on most of the points they brought across since I have lived similar moments along my personal and professional career.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=o9yspCrKHV0&quot;&gt;TDD: Mi libro de recetas&lt;/a&gt; &lt;a href=&quot;https://twitter.com/msanjuan&quot;&gt;Modesto Sanjuan&lt;/a&gt;
Modesto made a very practical talk about why he uses TDD and some tools to avoid some of it pitfalls. Very interesting discussions were raised about naming, test structuring and assertions that made me reassess my knowledge about TDD.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2-ILyErMUuQ&quot;&gt;The Economics of Continuous Delivery&lt;/a&gt; &lt;a href=&quot;https://twitter.com/eidrien&quot;&gt;Adrian Perreau&lt;/a&gt;
Adrian presented a very interesting and mathematical approach on how to sell Continuous Delivery to stakeholders in the language they most commonly understand, MONEY! 
With the aid of  some mathematical formulas he showed us how to calculate the effort and money needed in traditional Integration and Delivery compared with Continuous Delivery. (Hint: Continuous Delivery is the clear winner)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cw6Va1ZW7iI&quot;&gt;Clean Code, SOLID, CQRS… ¿Y qué hay de nuestros test?&lt;/a&gt; &lt;a href=&quot;https://twitter.com/rafaoe&quot;&gt;Rafa Gómez&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/JavierCane&quot;&gt;Javi Ferrer&lt;/a&gt;
On their very fun and interesting talk, Rafa and Javi talked about how to test our CQRS architectures. They made a good introduction of the different types of tests they normally use when developing CQRS applications, when they prefer to use them. They also introduced some really interesting test anti-patterns with seriously cool names.&lt;/p&gt;

&lt;h2 id=&quot;event-organisation-and-food&quot;&gt;Event Organisation and Food&lt;/h2&gt;

&lt;p&gt;I would like to take the time to thank again the organisers, they made such a great event possible. We know that growing from 80 to 200 people is not easy but they succeeded. There was always one organiser available when I needed assistance and I always knew what was going on.&lt;/p&gt;

&lt;p&gt;I really liked the venue, even if it is not in the most centric part of Barcelona, we had well sized rooms that and some green areas where we could get out and relax. The food during the day was also a high point, with fruit and drinks readily available.&lt;/p&gt;

&lt;h2 id=&quot;the-community&quot;&gt;The community&lt;/h2&gt;

&lt;p&gt;I would also like to thank the Software Craftsmanship community, I am proud to belong to such a group of people where we find a safe space to talk about how to continue improving on both our professional and personal facets of our lives. I have joined many interesting hall talks and finally devirtualized people like &lt;a href=&quot;https://twitter.com/bberrycarmen&quot;&gt;Rachel&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/msanjuan&quot;&gt;Modesto&lt;/a&gt;. I leave the event with more desire to continue learning than ever. Will be back!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/scbcn17-group.jpeg&quot; alt=&quot;Group Picture&quot; /&gt;&lt;/p&gt;
</description>
          <pubDate>2017-11-08T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/11/software-craftsmanship-bcn-2017</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/11/software-craftsmanship-bcn-2017</guid>
        </item>
      
    
      
        <item>
          <title>Flejesai 2017 Edición de Otoño</title>
          <description>&lt;h2 id=&quot;qué-es-dónde-y-por-qué&quot;&gt;Qué es, dónde y por qué&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/flejesai2017-2-borines.jpg&quot; alt=&quot;Vistas al valle de Borines&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hace dos semanas organizamos el Flejesai, edición Otoño 2017.  Desde que se fundó Codesai el año pasado nos reunimos cada seis meses para vernos, charlar de temas importantes que se hablan mejor en persona y sobre todo fortalecer los lazos que en una empresa totalmente remota hay que cuidar de manera especial.&lt;/p&gt;

&lt;p&gt;Es el tercero al que asisto, y después de Las Palmas de Gran Canaria y Madrid, ya tenía ganas de traer a mis compañeros a Asturias. Estoy especialmente orgulloso de lo que puede ofrecer esta tierra.&lt;/p&gt;

&lt;p&gt;Además de lo típico en lo que todos estaréis pensando, paisajes y buena comida, lo que realmente me hacía desear hacer un Flejesai aquí, era que quería invitar a mis compañeros a mi pueblo, en Borines.&lt;/p&gt;

&lt;p&gt;El cariño que siento por este rincón, la casa en la que nació mi madre y en la que paso muchos fines de semana, no disminuye con el tiempo, y nunca me acostumbraré a las vistas del valle que puedo ver desde la terraza, sí, es la que veis en la foto de arriba.
Pues todo esto quería compartir con mis compañeros.&lt;/p&gt;

&lt;h2 id=&quot;la-organización&quot;&gt;La organización&lt;/h2&gt;

&lt;p&gt;El evento que queríamos hacer consistía en dos días enteros de charla, por tanto las llegadas y salidas serían el día anterior y posterior. No es poca cosa pensar en todo lo necesario para 11 personas durante cuatro días.&lt;/p&gt;

&lt;p&gt;Lo primero fue valorar si podíamos hacer nuestro evento allí, en la casa familiar, y llegamos a la conclusión que no era un buen lugar. Hay que reconocer que no es precisamente un centro de empresas e íbamos a estar un tanto incómodos tantas personas hablando mucho tiempo, queriendo proyectar, etc.&lt;/p&gt;

&lt;p&gt;Afortunadamente, a unos 10 minutos caminando encontramos una casa rural que nos iba a resolver tanto alojamiento como salas de reuniones. El resto de la preparación consistió en garantizar que nuestro mayor foco estuviese en hablar de nuestras cosas, así que todas la comidas o las encargamos o fuimos a disfrutarlas a algún sitio cercano.&lt;/p&gt;

&lt;h2 id=&quot;y-empezamos&quot;&gt;Y empezamos…&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/flejesai2017-2-kitchen-moment.jpg&quot; alt=&quot;Reunión en la cocina&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Con todo ya listo llegó el gran día.
Los dos objetivos principales eran hablar de los temas que traíamos en la agenda y pasar mucho tiempo juntos, charlando.&lt;/p&gt;

&lt;p&gt;De lo primero hubo mucho, hablamos largo y tendido de lo que nos preocupa y tomamos decisiones que ayudarán a seguir fortaleciendo este equipo y afiancen el futuro de nuestra pequeña organización. Luego os comentaré alguna.&lt;/p&gt;

&lt;p&gt;De la parte de charla y ocio, menos de lo que nos hubiese gustado. Conversamos mucho entre nosotros, teniendo algún ‘café’ y pudimos conocernos un poco más.  Creamos el meme ‘Quiero saber a qué dedica su tiempo libre X’. Puede que un poco forzado, pero entrábamos al trapo, cómo no.
Aunque en la retrospectiva estuvimos de acuerdo en que haría falta fijar mejor los horarios de la agenda, reuniones y descansos, para así manejar mejor las expectativas de tiempo libre. Hubo muchos tiempos muertos en los que se nos iba la energía: “¿Paramos o seguimos? … (sloths everywhere)”&lt;/p&gt;

&lt;h2 id=&quot;resultados&quot;&gt;Resultados&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/flejesai2017-2-team.jpg&quot; alt=&quot;Team&quot; /&gt;&lt;/p&gt;

&lt;p&gt;¿Qué me llevo? (pregunta clásica): mucho.&lt;/p&gt;

&lt;p&gt;La mayoría de los temas tratados han sido sobre organización interna, en mi opinión quizá demasiados. Se nota que somos una empresa joven y que hay todavía cimientos que afianzar.&lt;/p&gt;

&lt;p&gt;Sí empezamos a hablar de algunos puntos más estratégicos y de cultura que me gustaría seguir trabajando ya poco a poco con el equipo los próximos meses.&lt;/p&gt;

&lt;p&gt;El primero que destacaría fue el de la asistencia a eventos y presentar charlas, si las vemos necesarias y a cuáles ir. Todos sentimos que tienen un gran coste en muchos aspectos: económico, de tiempo, familiar, …&lt;/p&gt;

&lt;p&gt;Este tema nos llevó a uno más general, sobre qué estrategia de marketing tenemos, el cómo nos damos a conocer. Porque vimos que ir a eventos es una herramienta más, como el blog, la organización de cursos, la participación en comunidades locales o el trabajo más comercial de contacto directo con clientes interesantes con los que colaborar.&lt;/p&gt;

&lt;p&gt;Salió la idea de organizar un curso en abierto de “TDD Avanzado”, que ya lo está reclamando mucha gente, y uno de “Refactoring”, pues ya se está impartiendo a empresas.&lt;/p&gt;

&lt;p&gt;El segundo punto que destacaría de los temas tratados, es definir mejor nuestra estrategia de formación interna. Fue breve, pero sacamos alguna idea para potenciar lo que considero una de las características que nos definen, el aprendizaje continuo. Actualmente hacemos pairing casi constante y repartimos pequeñas píldoras de conocimiento entre las personas que estamos en el mismo proyecto, pero nos faltaría algo más a medio plazo a nivel de todo el grupo. 
De aquí salieron ideas como clubes de lectura, katas los viernes, mentoring y charlas internas, … realmente muy potente.&lt;/p&gt;

&lt;h2 id=&quot;sensaciones&quot;&gt;Sensaciones&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/flejesai2017-2-cider-post.jpg&quot; alt=&quot;Paseo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Cuando nos despedíamos, nos decíamos unos a otros que fue el mejor Flejesai que habíamos hecho hasta ahora. Nos fuimos muy unidos y con mucha energía.&lt;/p&gt;

&lt;p&gt;Es que el concepto de ‘retiro’ en casa rural es el que necesitamos, es importante que todos durmamos en el mismo sitio, ser prácticos es menos importante que maximizar las oportunidades de conversación.&lt;/p&gt;

&lt;p&gt;Y por supuesto, lo que pasa en el Flejesai, se queda en el Flejesai. Sobre todo lo que a ‘karaokes’ hasta las cinco de la mañana se refiere.&lt;/p&gt;

&lt;p&gt;¡Y ahora a gastar esa energía!&lt;/p&gt;

&lt;p&gt;Por cierto, una de las decisiones fue que el próximo Flejesai será en febrero/marzo en Tenerife, que no es Asturias, pero tampoco está nada mal, ¿no os parece?&lt;/p&gt;
</description>
          <pubDate>2017-10-20T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/10/flejesai-2017-autumn-edition</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/10/flejesai-2017-autumn-edition</guid>
        </item>
      
    
      
        <item>
          <title>In a small piece of code</title>
          <description>&lt;p&gt;In a &lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;previous post&lt;/a&gt; we talked about &lt;em&gt;positional parameters&lt;/em&gt; and how they can suffer from &lt;strong&gt;Connascence of Position, (CoP)&lt;/strong&gt;. Then we saw how, in some cases, we might introduce &lt;em&gt;named parameters&lt;/em&gt; to remove the &lt;em&gt;CoP&lt;/em&gt; and transform it into &lt;strong&gt;Connascence of Name, (CoN)&lt;/strong&gt;, but always being careful to not hiding cases of &lt;strong&gt;Connascence of Meaning, (CoM)&lt;/strong&gt;. In this post we’ll focus on languages that don’t provide &lt;em&gt;named parameters&lt;/em&gt; and see different techniquess to remove the CoP.&lt;/p&gt;

&lt;p&gt;Let’s see an example of a method suffering of CoP:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/eb06db1754f89b18adc60069f03a841e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In languages without &lt;em&gt;named parameters&lt;/em&gt; (the example is written in Java), we can apply a classic&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; refactoring technique, &lt;a href=&quot;https://refactoring.com/catalog/introduceParameterObject.html&quot;&gt;Introduce Parameter Object&lt;/a&gt;, that can &lt;strong&gt;transform CoP into CoN&lt;/strong&gt;. In this example, we introduced the &lt;em&gt;ClusteringParameters&lt;/em&gt; object:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/95636f3eeca5d476d383869240763cca.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;which eliminates the CoP transforming it into CoN:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1cb8b24f085cb6993b2eaa59ff60e895.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In this particular case, all the parameters passed to the function were semantically related, since they all were parameters of the clustering algorithm, but in many other cases all the parameters aren’t related. So, as we saw in our &lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;previous post&lt;/a&gt; for &lt;em&gt;named parameters&lt;/em&gt;, we have to be careful of not accidentally sweeping hidden CoM in the form of &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;data clumps&lt;/a&gt; under the rug when we use the &lt;a href=&quot;https://refactoring.com/catalog/introduceParameterObject.html&quot;&gt;Introduce Parameter Object&lt;/a&gt; refactoring.&lt;/p&gt;

&lt;p&gt;In any case, what it’s clear is that &lt;strong&gt;introducing a parameter object produces much less expressive code than introducing named parameters&lt;/strong&gt;. So how to &lt;em&gt;gain semantics while removing CoP&lt;/em&gt; in languages without &lt;em&gt;named parameters&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;One answer is using &lt;a href=&quot;https://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interfaces&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; which is a technique that is much more common than you think. Let’s have a look at the following small piece of code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/26422c2a60a7ec79be7422e561c435ff.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is just a simple test. However, just in this small piece of code, we can find two examples of removing &lt;em&gt;CoP&lt;/em&gt; using &lt;a href=&quot;https://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interfaces&lt;/a&gt; and another example that, while not removing &lt;em&gt;CoP&lt;/em&gt;, completely removes its impact on expressiveness. Let’s look at them with more detail.&lt;/p&gt;

&lt;p&gt;The first example is an application of the &lt;a href=&quot;http://wiki.c2.com/?BuilderPattern&quot;&gt;builder pattern&lt;/a&gt; using a &lt;em&gt;fluent interface&lt;/em&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d42762b85c695226f069430214d69110.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Applying the &lt;em&gt;builder pattern&lt;/em&gt; provides a very specific&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt; &lt;a href=&quot;https://martinfowler.com/bliki/InternalDslStyle.html&quot;&gt;internal DSL&lt;/a&gt; that we can use to create a complex object avoiding CoP and also getting an expressiveness comparable or even superior to the one we’d get using &lt;em&gt;named parameters&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this case we composed two builders, one for the &lt;em&gt;SafetyRange&lt;/em&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d7eab5609348590f7eb070edad4017c1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;and another for the &lt;em&gt;Alarm&lt;/em&gt; class:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/def882d4489f9906408b3c1626a23057.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;em&gt;Composing builders&lt;/em&gt; you can manage to create very complex objects in a maintanable and very expressive way.&lt;/p&gt;

&lt;p&gt;Let’s see now the second interesting example in our small piece of code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/948bd5895f903f2b7ac9a22bfc18a5e6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This assertion using &lt;a href=&quot;https://code.google.com/archive/p/hamcrest/wikis/Tutorial.wiki&quot;&gt;hamcrest&lt;/a&gt; is so simple that the &lt;a href=&quot;http://junit.org/junit5/&quot;&gt;JUnit&lt;/a&gt; alternative is much clearer:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8127ee504363613bacd7d3a0e5925f03.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;but for more than one parameter the &lt;em&gt;JUnit&lt;/em&gt; interface starts having problems:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/55d79c4b44d4df309b8cc9d92550a3ad.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Which one is the &lt;em&gt;expected value&lt;/em&gt; and which one is the &lt;em&gt;actual one&lt;/em&gt;? We never manage to remember…&lt;/p&gt;

&lt;p&gt;Using &lt;em&gt;hamcrest&lt;/em&gt; removes that expressiveness problem:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a93a36a190009b1ee8a9946b9754d16a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Thanks to the semantics introduced by &lt;em&gt;hamcrest&lt;/em&gt;&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;, it’s very clear that the first parameter is the actual value and the second parameter is the expected one. The &lt;em&gt;internal DSL&lt;/em&gt; defined by &lt;em&gt;hamcrest&lt;/em&gt; produces declarative code with high expressiveness. To be clear &lt;strong&gt;hamcrest is not removing the CoP&lt;/strong&gt;, but since there are only two parameters, the degree of CoP is very low&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;. The real problem of the code using the &lt;em&gt;JUnit&lt;/em&gt; assertion was its low expressiveness and using &lt;em&gt;hamcrest&lt;/em&gt; fixes that.&lt;/p&gt;

&lt;p&gt;For us it’s curious to see how, in &lt;em&gt;trying to achieve expressiveness&lt;/em&gt;, some assertion libraries that use &lt;em&gt;fluent interfaces&lt;/em&gt; have (probably not being aware of it) eliminate CoP as well. See this other example using &lt;a href=&quot;https://jasmine.github.io/&quot;&gt;Jasmine&lt;/a&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2c205cd115015baceace3a5483ac23c5.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Finally, let’s have a look at the last example in our initial small piece of code which is also using a &lt;em&gt;fluent interface&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/168c5a69b6faf8443789d5f7c9a5a75b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is &lt;a href=&quot;http://site.mockito.org/&quot;&gt;Mockito&lt;/a&gt;’s way of defining a stub for a method call. It’s another example of &lt;em&gt;fluent interface&lt;/em&gt; which produces highly expressive code and avoids CoP.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary.&lt;/h3&gt;
&lt;p&gt;We started seeing how, in languages that don’t allow &lt;em&gt;named parameters&lt;/em&gt;, we can remove CoP by applying the &lt;em&gt;Introduce Parameter Object&lt;/em&gt; refactoring and how the resulting code was much less expressive than the one using the &lt;em&gt;Introducing Named Parameters&lt;/em&gt; refactoring. Then we saw how we can leverage &lt;em&gt;fluent interfaces&lt;/em&gt; to remove CoP while writing highly expressive code, mentioned internal DSLs and showed you how this technique is more common that one can think at first by examining a small piece of code.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References.&lt;/h3&gt;

&lt;h4 id=&quot;books&quot;&gt;Books.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/books/refactoring.html&quot;&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;, Martin Fowler&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software Guided by Tests&lt;/a&gt;, Nat Pryce and Steve Freeman.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/books/refactoringRubyEd.html&quot;&gt;Refactoring Ruby&lt;/a&gt;, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;posts&quot;&gt;Posts.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&quot;&gt;Refactoring Ruby: Bad Smells in Code&lt;/a&gt;, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://aphyr.com/posts/321-builders-vs-option-maps&quot;&gt;Builders vs option maps&lt;/a&gt;, Kyle Kingsbury&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2016/10/refactoring-tests-using-builder-functions-in-clojure-clojureScript&quot;&gt;Refactoring tests using builder functions in Clojure/ClojureScript&lt;/a&gt;, Manuel Rivero&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2015/07/remove-data-structures-noise-from-your-tests-with-builders&quot;&gt;Remove data structures noise from your tests with builders&lt;/a&gt;, Carlos Blé&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;Two examples of Connascence of Position&lt;/a&gt;, Manuel Rivero, Fran reyes&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2017/01/about-connascence&quot;&gt;About Connascence&lt;/a&gt;, Manuel Rivero&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt;&apos;s &lt;a href=&quot;https://martinfowler.com/books/refactoring.html&quot;&gt;Refactoring, Improving the Design of Existing Code&lt;/a&gt; book.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Of course, &lt;i&gt;fluent interfaces&lt;/i&gt; are also great in languages that provide &lt;i&gt;named parameters&lt;/i&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] Curiosly there&apos;re alternative ways to implement the &lt;i&gt;builder pattern&lt;/i&gt; that use &lt;a href=&quot;https://aphyr.com/posts/321-builders-vs-option-maps&quot;&gt;options maps&lt;/a&gt; or &lt;a href=&quot;https://stackoverflow.com/questions/12633670/whats-the-clojure-way-to-builder-pattern&quot;&gt;named parameters&lt;/a&gt;. Some time ago we wrote about an example of using the second way: &lt;a href=&quot;/2016/10/refactoring-tests-using-builder-functions-in-clojure-clojureScript&quot;&gt;Refactoring tests using builder functions in Clojure/ClojureScript&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] The only purpose of that DSL is creating one specific type of object.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] For us the best explanation of the &lt;i&gt;builder pattern&lt;/i&gt; and how to use it to create maintanable tests is in chapter 22, &lt;b&gt;Constructing Complex Test Data&lt;/b&gt;, of the wonderful &lt;a href=&quot;http://www.growing-object-oriented-software.com/&quot;&gt;Growing Object-Oriented Software Guided by Tests book&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] &lt;i&gt;hamcrest&lt;/i&gt; is a framework for writing matcher objects allowing &apos;match&apos; rules to be defined declaratively. We love it!
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] See our &lt;a href=&quot;/2017/07/two-examples-of-connascence-of-position&quot;&gt;previous post about CoP&lt;/a&gt;.
&lt;/div&gt;
</description>
          <pubDate>2017-08-22T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/08/cop-builders-and-fluid-interfaces</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/08/cop-builders-and-fluid-interfaces</guid>
        </item>
      
    
      
        <item>
          <title>Notes on SRP from Agile Principles, Practices and Patterns book</title>
          <description>&lt;p&gt;I think that if you rely only on talks, community events, tweets and posts to learn about a concept, you can sometimes end up with diluted (or even completely wrong) versions of the concept due to broken telephone game effects. For this reason, I think it’s very useful to try to get closer to the sources of the concepts you want to learn.&lt;/p&gt;

&lt;p&gt;Lately I’ve been doing an effort to get closer to the sources of some object-oriented concepts.&lt;/p&gt;

&lt;p&gt;These are my notes on &lt;b&gt;Single Responsibility Principle&lt;/b&gt; I’ve taken from the chapter devoted to it in &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_Cecil_Martin&quot;&gt;Robert C. Martin&lt;/a&gt;’s wonderful &lt;a href=&quot;https://www.goodreads.com/book/show/84983.Agile_Principles_Patterns_and_Practices_in_C_&quot;&gt;Agile Principles, Practices and Patterns in C#&lt;/a&gt; book:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt; 
        &quot;This principle was described in the work of [&lt;a href=&quot;https://en.wikipedia.org/wiki/Larry_Constantine&quot;&gt;Larry Constantine&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Edward_Yourdon&quot;&gt;Ed Yourdon&lt;/a&gt;,] &lt;a href=&quot;https://en.wikipedia.org/wiki/Tom_DeMarco&quot;&gt;Tom DeMarco&lt;/a&gt; and &lt;a href=&quot;http://www.construx.com/Employees/Meilir_Page-Jones/&quot;&gt;Meilir Page-Jones&lt;/a&gt;. They called it &lt;b&gt;cohesion&lt;/b&gt;, which they defined as &lt;b&gt;the functional relatedness of the elements of a module&lt;/b&gt;&quot; &amp;lt;- [!!!]
    &lt;/li&gt;

    &lt;li&gt;
        &quot;... we modify that meaning a bit and &lt;b&gt;relate cohesion to the forces that cause a module, or a class, to change&lt;/b&gt;&quot;
    &lt;/li&gt;

    &lt;li&gt;
        [SRP definition] -&amp;gt; &quot;&lt;b&gt;A class should have only one reason to change&lt;/b&gt;&quot;
    &lt;/li&gt;

    &lt;li&gt;
        &quot;Why was important to separate [...] responsibilities [...]? The reason is that each responsibility is an &lt;b&gt;axis of change&lt;/b&gt;&quot; &amp;lt;- [related with &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt;&apos;s &lt;b&gt;complexity dimensions&lt;/b&gt;]
    &lt;/li&gt;

    &lt;li&gt;
        &quot;&lt;b&gt;If a class has more than one responsibility the responsibilities become coupled&lt;/b&gt;&quot; &amp;lt;- [related with &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=2&quot;&gt;Long Method&lt;/a&gt;, &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=3&quot;&gt;Large Class&lt;/a&gt;, etc.] &amp;lt;- [It also eliminates the possibility of using composition at every level (functions, classes, modules, etc.)] &quot;Changes to one responsibility may impair or inhibit the class ability to meet the others. This kind of coupling leads to &lt;b&gt;fragile designs&lt;/b&gt;&quot; &amp;lt;- [For R. C. Martin, fragility is a design smell, &lt;b&gt;a design is fragile when it&apos;s easy to break&lt;/b&gt;]
    &lt;/li&gt;

    &lt;li&gt;[Defining what responsibility means]
        &lt;ul&gt;
            &lt;li&gt;
                &quot;In the context of the SRP, we define a responsibility to be &lt;b&gt;a reason for change&lt;/b&gt;&quot;
            &lt;/li&gt;

            &lt;li&gt;
                &quot;If you can think of more than one motive for changing a class, that class has more than one responsibility. This is sometimes difficult to see&quot;
            &lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;

    &lt;li&gt;
        &quot;&lt;b&gt;Should [...] responsibilities be separated?&lt;/b&gt; That &lt;b&gt;depends on how the application is changing&lt;/b&gt;. &lt;b&gt;If the application is not changing in ways that cause the [...] responsibilities to change at different times, there is no need to separate them.&lt;/b&gt;&quot; &amp;lt;- [applying &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Beck&lt;/a&gt;&apos;s &lt;b&gt;Rate of Change&lt;/b&gt; principle from &lt;a href=&quot;https://www.goodreads.com/book/show/781559.Implementation_Patterns&quot;&gt;Implementation Patterns&lt;/a&gt;] &quot;Indeed separating them would smell of &lt;b&gt;needless complexity&lt;/b&gt;&quot; &amp;lt;- [&lt;b&gt;Needless Complexity&lt;/b&gt; is a design smell for R. C. Martin. It&apos;s equivalent to &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=13&quot;&gt;Speculative Generality&lt;/a&gt; from &lt;a href=&quot;https://www.goodreads.com/book/show/44936.Refactoring&quot;&gt;Refactoring&lt;/a&gt; book]
    &lt;/li&gt;

    &lt;li&gt;
        &quot;&lt;b&gt;An axis of change is an axis of change only if the changes occur&lt;/b&gt;&quot; &amp;lt;- [relate with &lt;b&gt;Speculative Generality&lt;/b&gt; and &lt;a href=&quot;http://wiki.c2.com/?YouArentGonnaNeedIt&quot;&gt;Yagni&lt;/a&gt;] &quot;It&apos;s &lt;b&gt;not wise to apply SRP, or any other principle if there&apos;s no symptom&lt;/b&gt;&quot; &amp;lt;- [I think this applies at class and module level, but it&apos;s still worth it to &lt;i&gt;always try to apply SRP at method level&lt;/i&gt;, as a &lt;i&gt;responsibility identification and learning process&lt;/i&gt;]
    &lt;/li&gt;
 
    &lt;li&gt;
        &quot;There are often reasons, having to do with the details of hardware and the OS [example with a Modem implementing two interfaces DateChannel and Connection], that force us to couple things that we&apos;d rather not couple. However by &lt;b&gt;separating their interfaces&lt;/b&gt;, we [...] &lt;b&gt;decouple&lt;/b&gt;[..] the &lt;b&gt;concepts as far as the rest of the application is concerned&lt;/b&gt;&quot; &amp;lt;- [Great example of using &lt;b&gt;ISP&lt;/b&gt; and &lt;b&gt;DIP&lt;/b&gt; to hide complexity to the clients] &quot;We may view [Modem] as a kludge, however, note that all dependencies flow away from it.&quot; &amp;lt;- [thanks to &lt;b&gt;DIP&lt;/b&gt;] &quot;Nobody needs to depend on this class [Modem]. Nobody except main needs to know it exists&quot; &amp;lt;- [main is the entry point where the application is configured using dependency injection] &quot;Thus we&apos;ve put the ugly bit behind a fence. It&apos;s ugliness need not leak out and pollute the rest of the app&quot;
    &lt;/li&gt;

    &lt;li&gt;
        &quot;SRP is one of the simplest of the principles but one of the most difficult to get right&quot;
    &lt;/li&gt;

    &lt;li&gt;
        &quot;Conjoining responsibilities is something that we do naturally&quot;
    &lt;/li&gt;

    &lt;li&gt;
        &quot;Finding and separating those responsibilities is much of what software design is really about. Indeed the rest of the principles we discuss come back to this issue in one way or another&quot;
    &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/84983.Agile_Principles_Patterns_and_Practices_in_C_&quot;&gt;Agile Principles, Practices and Patterns in C#&lt;/a&gt; is a great book that I recommend to read.&lt;/p&gt;

&lt;p&gt;For me getting closer to the sources of SOLID principles was a great experience that helped me to remove illusions of knowledge I had developed due to the telephone game effect of having initially learned it through blogs and talks.&lt;/p&gt;

&lt;p&gt;I hope these notes on SRP will be useful for you as well.&lt;/p&gt;
</description>
          <pubDate>2017-08-17T11:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/08/notes-on-srp</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/08/notes-on-srp</guid>
        </item>
      
    
      
        <item>
          <title>Comentarios en el código</title>
          <description>&lt;p&gt;¿Comentamos el código? ¿si o no? Esa pregunta totalmente desprovista de
contexto no puede tener una respuesta con la que esté de acuerdo todo 
el mundo. Sin más contexto, la discusión es inútil. La pregunta realmente
es, ¿cuándo documentar el código?.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;El objetivo de los comentarios NO es explicar lo que hace el código&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El código debe ser expresar con claridad lo que hace sin necesidad de 
 comentarios, para lo cual disponemos de variables explicativas, funciones
 y métodos, clases, objetos, y un sin fin de recursos para que el código
 sea expresivo y no se requiera lenguaje natural para contar lo que hace. 
 El problema de los comentarios que explican lo que está haciendo 
 el código, es que son una excusa perfecta para escribir
 código que no entiende nadie. Con el tiempo el código se actualiza y 
 cambia, pero nunca he conocido a nadie que actualizase los comentarios.
 Con lo cual llega un momento en que nos encontramos con un código
 tremendamente difícil de entender y que además tiene unas líneas de 
 comentario por encima que mienten. Los comentarios están diciendo que 
 el código hace algo que no hace. Doble dilema, código que nadie entiende
 y comentarios para despistar más todavía.&lt;/p&gt;

&lt;p&gt;Cada vez que uno siente la necesidad de poner un comentario sobre un
 bloque de líneas de código, es una oportunidad para pensar si se puede
 extraer una función que tenga por nombre lo mismo que se iba a escribir
 en el comentario. Sobre todo estos bloques típicos que tienen una sospechosa línea en blanco al terminar, como para separarlo del siguiente bloque de código. Esto canta a función/método.&lt;/p&gt;

&lt;p&gt;El código se escribe para que lo lean las personas, no las máquinas, ya
 que son personas quienes tendrán que mantenerlo. Los comentarios han 
 hecho tanto daño que hemos acabando yendo al lado opuesto, a no escribir
 jamás ningún tipo de comentario. Y de esto quería hablar en este post, 
 de lo mucho que hecho de menos los comentarios y la documentación en 
 los proyectos. Por que los &lt;strong&gt;comentarios son muy útiles para contar
 el contexto&lt;/strong&gt;, cosa que el código en sí no puede contar por más limpio que sea.
 Los comentarios nos permiten:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Explicar por qué, para qué y también por qué no, y qué evitar.&lt;/li&gt;
  &lt;li&gt;Por qué se decidió implementar concretamente de la manera que está.&lt;/li&gt;
  &lt;li&gt;Por qué se descartó implementarlo de otra manera que quizás parece más obvia o natural.&lt;/li&gt;
  &lt;li&gt;Para qué se usa ese código, dónde encaja, qué otros posibles usos podría tener. Si existe alguna situación en la que pudiera ser prescindible y borrarse.&lt;/li&gt;
  &lt;li&gt;Lo que se probó y no funcionó, para que no vuelva a invertir el tiempo la persona que viene.&lt;/li&gt;
  &lt;li&gt;Lo que se estudió y se descartó. Cuáles fueron las conclusiones de la investigación.&lt;/li&gt;
  &lt;li&gt;Los efectos colaterales que provocarían cambios aparentemente inocuos. Por ejemplo condiciones de carrera o interbloqueos al cambiar de orden dos líneas de código. Un salto de línea que parece insignificante y hace
  que luego la importación de un fichero en un sistema externo deje de funcionar…&lt;/li&gt;
  &lt;li&gt;Si existen parámetros globales de configuración u otros factores externos que podrían afectar a este código o que haya que tener en cuenta para
  su correcto funciomaniento.&lt;/li&gt;
  &lt;li&gt;Si en caso de fallo se puede ir a mirar algún tipo de log o cualquier otra forma de depuración. Sobre todo en tests de integración.&lt;/li&gt;
  &lt;li&gt;Si el sistema puede crecer hasta un punto en que el código dejará de servir. Es decir, si hemos elegido una solución potencialmente de corto recorrido. Por ejemplo una librería que ya no tiene soporte o un sistema que sólo aguantará hasta N usuarios.&lt;/li&gt;
  &lt;li&gt;Ayudar a entender cómo se comporta una librería o framework cuando interactuamos de cierta forma que podría no estar documentada o ser poco intuitiva.&lt;/li&gt;
  &lt;li&gt;Sorpresas de software de terceros, para que sólo nos la llevemos una vez.&lt;/li&gt;
  &lt;li&gt;Describir un API pública de propósito general.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No es que haya que hablar sobre todos los elementos de esta lista en todos los casos. Algunos de estos criterios serán aplicables a veces y otras no. Creo que es evidente
que no todo bloque de código llevará comentarios ni muchísimo menos. Todavía oigo a gente decir que todas las rutinas deben llevar comentarios. Así sin más, no tiene sentido. Cuando pongo comentarios además me gusta poner la fecha, aunque se podría 
mirar en el control de versiones pero me resulta más rápido. Cuanto más viejo el 
comentario más posibilidades hay de que esté obsoleto. Quizás podría tener sentido
poner el nombre del que escribe el comentario como para que otros puedan tener una 
conversación, aunque la verdad yo no lo hago. Sobre todo porque la mayor parte la
hacemos en pares.&lt;/p&gt;

&lt;p&gt;¿Y qué hay de los comentarios de cabecera tipo &lt;em&gt;javadoc&lt;/em&gt;? Me refiero a los comentarios 
que se ponen para las herramientas de generación de documentación automática o para el IDE. En 
lenguajes compilados donde podemos hacer uso de nuestros propios tipos, podemos ahorrarnos muchos de esos comentarios. Cuando se trata del núcleo de
lógica de negocio, si usamos tipos con un nombre expresivo en lugar de abusar de los
primitivos, no hace falta describir el parámetro. Y es que abusamos muchísimo de los primitivos, que deberían quedar relegados a intercambio de información con sistemas
de terceros y a detalles internos de implementación.
Personalmente solo documento funciones
de APIs que tengan un propósito general, un uso muy horizontal. Por ejemplo cuando he 
hecho alguna librería. 
Con lenguajes interpretados como PHP, poner cabeceras en las 
funciones con los tipos ayuda a que el IDE autocomplete e indexe mejor. 
Si el comentario aporta un contexto que el código en sí no puede aportar y de verdad
no es redundante, es buena idea describir los parámetros de la función y el valor 
de retorno. Lo que evitaría, nuevamente, es ponerlos siempre en todos los casos aunque
sea redundante y para que esté sirviendo de excusa para no diseñar un sistema de clases
acorde al dominio.&lt;/p&gt;

&lt;p&gt;Los tests son igual de importantes que el código de producción, por lo tanto aplica también
la documentación y posibles comentarios. De hecho algunos de los principios de esta lista
están extraídos de los tests. Por ejemplo documentar que no se pueden lanzar en paralelo porque
se ha introducido deuda técnica que provocaría que fallasen. O explicar que son frágiles porque
dependen de esto o aquello que podría cambiar. Suele tener que ve con deuda técnica y código
legacy donde hay cajas de pandora ocultas. La idea es al menos hacerlas visibles.&lt;/p&gt;

&lt;p&gt;Toda excepción tiene su regla. Me he encontrado con la necesidad de comentar código 
legado que era muy difícil de entender, escrito por personas que ya no estaban 
en la empresa. Código que no mejoraba apenas aplicando refactorings 
seguros como podría ser un renombrado o una extracción de método. Y sin tener&lt;br /&gt;
la capacidad de cambiarlo por miedo a romperlo, he comentado lo que he podido 
descifrar con paciencia. Depurando, con prueba y error. Aunque sepa que en el 
momento que tenga unos tests podré cambiar el código y prescindir de esos 
comentarios, en el momento del hallazgo aporta a todo el equipo dejar algo 
más entendible escrito. Se puede aprovechar a explicar los motivos que han llevado
a tener que explicar el código en lenguaje natural.&lt;/p&gt;

&lt;p&gt;Además de los comentarios, hay cuestiones transversales que es importante documentar. 
Ya no solo temas de infraestructura o deuda técnica, sino todo aquello que nos ayude
a ser más productivos como podría ser ejecutar los tests desde el propio IDE o afinar
bien cualquier otra herramienta. Se pueden usar wikis o simplemente ficheros markdown
versionados en la raíz del propio código fuente. Más tarde o más temprano, la 
documentación quedará obsoleta pero por el camino habrá sido de utilidad al equipo.&lt;/p&gt;

&lt;p&gt;En definitiva amigos del código limpio, &lt;strong&gt;os invito a tener más presentes los comentarios
y la documentación&lt;/strong&gt; porque a nadie le gusta perder el tiempo más de una vez en descifrar
la misma cosa. Es frustrante y desagradecido. Y porque el mejor código del mundo no tiene 
la capacidad de contarnos cuál es su contexto.&lt;/p&gt;

</description>
          <pubDate>2017-08-03T11:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/08/comentarios-en-codigo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/08/comentarios-en-codigo</guid>
        </item>
      
    
      
        <item>
          <title>Two examples of Connascence of Position</title>
          <description>&lt;h3 id=&quot;a-first-example&quot;&gt;A first example.&lt;/h3&gt;

&lt;p&gt;As we saw in &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;our previous post about connascence&lt;/a&gt;, &lt;strong&gt;Connascence of Position (CoP)&lt;/strong&gt; happens &lt;strong&gt;when multiple components must be adjacent or appear in a particular order&lt;/strong&gt;. &lt;strong&gt;CoP&lt;/strong&gt; is the strongest form of static connascence, as shown in the following figure.&lt;/p&gt;

&lt;figure style=&quot;height:60%; width:60%;&quot;&gt;
    &lt;img src=&quot;/assets/connascence-o-meter.png&quot; alt=&quot;Connascence forms sorted by descending strength (from Kevin Rutherford&apos;s XP Surgery)&quot; /&gt;
    &lt;figcaption&gt;
      &lt;strong&gt;Connascence&lt;/strong&gt; forms sorted by descending strength (from &lt;a href=&quot;http://xpsurgery.eu/resources/connascence/&quot;&gt;Kevin Rutherford&apos;s XP Surgery&lt;/a&gt;).
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;A typical example of &lt;strong&gt;CoP&lt;/strong&gt; appears when we use &lt;em&gt;positional parameters&lt;/em&gt; in a method signature because any change in the order of the parameters will force to change all the clients using the method.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d72f1c05fdd0dffdc87c3da35e4ffe4d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The degree of the CoP increases with the number of parameters, being zero when we have only one parameter. This is closely related with the &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=4&quot;&gt;Long Parameters List smell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In some languages, such as Ruby, Clojure, C#, Python, etc, this can be refactored by introducing &lt;em&gt;named parameters&lt;/em&gt; (see &lt;a href=&quot;http://refactoring.com/catalog/introduceNamedParameter.html&quot;&gt;Introduce Named Parameter&lt;/a&gt; refactoring)&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c57de73f3fe2db22768fa63068617fb5.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Now changing the order of parameters in the signature of the method won’t force the calls to the method to change,
but changing the name of the parameters will. This means that the resulting method no longer presents CoP. Instead, now it presents &lt;strong&gt;Connascence of Name&lt;/strong&gt;, (CoN), which is the weakest form of static connascence, so this refactoring has reduced the overall connascence.&lt;/p&gt;

&lt;p&gt;The benefits don’t end there. If we have a look at the calls before and after the refactoring, we can see how the call after introducing &lt;em&gt;named parameters&lt;/em&gt; communicates the intent of each parameter much better. Does this mean that we should use &lt;em&gt;named parameters&lt;/em&gt; everywhere?&lt;/p&gt;

&lt;p&gt;Well, it depends. There’re some trade-offs to consider. &lt;em&gt;Positional parameters&lt;/em&gt; produce shorter calls. Using &lt;em&gt;named parameters&lt;/em&gt; gives us better code clarity and maintainability than &lt;em&gt;positional parameters&lt;/em&gt;, but we lose terseness&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;. On the other hand, when the number of parameters is small, a well chosen method name can make the intent of the &lt;em&gt;positional arguments&lt;/em&gt; easy to guess and thus make the use of &lt;em&gt;named parameters&lt;/em&gt; redundant.&lt;/p&gt;

&lt;p&gt;We should also consider the impact that the &lt;strong&gt;degree and locality of each instance of CoP&lt;/strong&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt; can have on the maintainability and communication of intent of each option. On one hand, the impact on maintainability of using &lt;em&gt;positional parameters&lt;/em&gt; is higher for public methods than for private methods (even higher for &lt;a href=&quot;https://martinfowler.com/bliki/PublishedInterface.html&quot;&gt;published public methods&lt;/a&gt;)&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. On the other hand, a similar reasoning might be made about the intent of &lt;em&gt;positional parameters&lt;/em&gt;: the &lt;em&gt;positional parameters&lt;/em&gt; of a private method in a cohesive class might be much easier to understand than the parameters of a public method of a class a client is using, because in the former case we have much more context to help us understand.&lt;/p&gt;

&lt;p&gt;The communication of &lt;em&gt;positional parameters&lt;/em&gt; can be improved a lot with the &lt;a href=&quot;https://www.youtube.com/watch?v=ZfYOddEmaRw&quot;&gt;parameter name hinting feature&lt;/a&gt; provided by IDEs like IntelliJ. In any case, even though they look like &lt;em&gt;named parameters&lt;/em&gt;, they still are &lt;em&gt;positional parameters&lt;/em&gt; and have CoP. In this sense, &lt;em&gt;parameter name hinting&lt;/em&gt; might end up having a bad effect in your code by reducing the pain of having &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=&quot;&gt;long parameter lists&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, moving to &lt;em&gt;named parameters&lt;/em&gt; can increase the difficulty of applying the most frequent refactoring: renaming. Most IDEs are great renaming &lt;em&gt;positional parameters&lt;/em&gt;, but not all are so good renaming &lt;em&gt;named parameters&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;a-second-example&quot;&gt;A second example.&lt;/h3&gt;

&lt;p&gt;There are also cases in which blindly using &lt;em&gt;named parameters&lt;/em&gt; can make things worse. See the following example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/60757f238bc92d986bbfc05dd1772d2b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The &lt;em&gt;activate_alarm&lt;/em&gt; method presents CoP, so let’s introduce &lt;em&gt;named parameters&lt;/em&gt; as in the previous example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1df94f2c27bc44d4cec4a2d884077d0d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We have eliminated the CoP and now there’s only CoN, right?&lt;/p&gt;

&lt;p&gt;In this particular case, the answer would be &lt;strong&gt;no&lt;/strong&gt;. We’re just masking the real problem which was a &lt;strong&gt;Connascence of Meaning (CoM)&lt;/strong&gt; (a.k.a. &lt;strong&gt;Connascence of Convention&lt;/strong&gt;). CoM happens &lt;strong&gt;when multiple components must agree on the meaning of specific values&lt;/strong&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;. CoM is telling us that there might be &lt;strong&gt;a missing concept or abstraction in our domain&lt;/strong&gt;. The fact that the &lt;em&gt;lower_threshold&lt;/em&gt; and &lt;em&gt;higher_threshold&lt;/em&gt; only make sense when they go together, (we’re facing a case of &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;data clump&lt;/a&gt;), is an implicit meaning or convention on which different methods sharing those parameters must agree, therefore there’s CoM.&lt;/p&gt;

&lt;p&gt;We can eliminate the CoM by introducing a new class, &lt;em&gt;Range&lt;/em&gt;, to wrap the &lt;em&gt;data clump&lt;/em&gt; and reify the missing concept in our domain reducing the CoM to Connascence of Type (CoT)&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;. This refactoring plus the introduction of named parameters leaves with the following code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5f3b86f7cb59cadc8f2a3ac962090fef.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This refactoring is way better than only introducing &lt;em&gt;named parameters&lt;/em&gt; because it does not only provides a &lt;strong&gt;bigger coupling reduction&lt;/strong&gt; by going down in the scale from from CoP to CoT instead of only from CoP to CoM, but also it &lt;strong&gt;introduces more semantics by adding a missing concept&lt;/strong&gt; (the &lt;em&gt;Range&lt;/em&gt; object).&lt;/p&gt;

&lt;p&gt;Later we’ll probably detect similarities&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt; in the way some functions that receives the new concept are using it and reduce it by moving that behavior into the new concept, converting it into a &lt;a href=&quot;https://martinfowler.com/bliki/ValueObject.html&quot;&gt;value object&lt;/a&gt;. It’s in this sense that we say that value objects attract behavior.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary.&lt;/h3&gt;
&lt;p&gt;We have presented two examples of CoP, a “pure” one and another one that was really hiding a case of CoM. We have related CoP and CoM with known code smells, (&lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=4&quot;&gt;Long Parameters List&lt;/a&gt;, &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;Data Clump&lt;/a&gt; and &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=9&quot;&gt;Primitive Obsession&lt;/a&gt;), and introduced refactorings to reduce their coupling and improve their communication of intent. We have also discussed a bit, about when and what we need to consider before applying these refactorings.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References.&lt;/h3&gt;
&lt;h4 id=&quot;talks&quot;&gt;Talks.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2016/12/charla-sobre-connascence-en-scbcn16&quot;&gt;Connascence&lt;/a&gt;, Fran Reyes &amp;amp; Alfredo Casado (&lt;a href=&quot;http://slides.com/franreyesperdomo/connascence#/&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;books&quot;&gt;Books.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/books/refactoringRubyEd.html&quot;&gt;Refactoring Ruby&lt;/a&gt;, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;posts&quot;&gt;Posts.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&quot;&gt;Refactoring Ruby: Bad Smells in Code&lt;/a&gt;, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://robots.thoughtbot.com/ruby-2-keyword-arguments&quot;&gt;Ruby 2 Keyword Arguments&lt;/a&gt;, Ian C. Anderson&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://silkandspinach.net/2012/09/03/the-problem-with-code-smells/&quot;&gt;The problem with code smells&lt;/a&gt;, Kevin Rutherford&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://silkandspinach.net/2014/09/19/a-problem-with-primitive-obsession/&quot;&gt;A problem with Primitive Obsession&lt;/a&gt;, Kevin Rutherford&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2017/01/about-connascence&quot;&gt;About Connascence&lt;/a&gt;, Manuel Rivero&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] For languages that don&apos;t allow &lt;i&gt;named parameters&lt;/i&gt;, see the &lt;a href=&quot;https://refactoring.com/catalog/introduceParameterObject.html&quot;&gt;Introduce Parameter Object&lt;/a&gt; refactoring.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] See &lt;a href=&quot;https://robots.thoughtbot.com/ruby-2-keyword-arguments&quot;&gt;Ruby 2.0 introduced keyword arguments&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] See our previous post &lt;a href=&quot;/2017/01/about-connascence&quot;&gt;About Connascence&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] For instance, &lt;a href=&quot;https://www.sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt; recommends in her &lt;a href=&quot;http://www.poodr.com/&quot;&gt;POODR book&lt;/a&gt; to &quot;use hashes for initialization arguments&quot; in constructors (this was the way of having named parameters before &lt;a href=&quot;https://robots.thoughtbot.com/ruby-2-keyword-arguments&quot;&gt;Ruby 2.0 introduced keyword arguments&lt;/a&gt;).
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=8&quot;&gt;Data Clump&lt;/a&gt; and &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=9&quot;&gt;Primitive Obsession&lt;/a&gt; smells are examples of CoM.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] Connascence of Type, (CoT), happens when multiple components must agree on the type of an entity. 
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Those similarities in the use of the new concept are examples of Conascence of Algorithm which happens when multiple components must agree on a particular algorithm.
&lt;/div&gt;
</description>
          <pubDate>2017-07-31T00:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/07/two-examples-of-connascence-of-position</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/07/two-examples-of-connascence-of-position</guid>
        </item>
      
    
      
        <item>
          <title>Aterrizando en un proyecto con legado</title>
          <description>&lt;p&gt;El equipo aterriza en nuevo proyecto para evolucionar un producto que lleva 5 años en producción, con un código legado que apenas tiene tests y donde no hay desarrolladores que lo conozcan a fondo. ¿Cómo nos organizamos para aportar el máximo valor?&lt;/p&gt;

&lt;p&gt;El contexto hace que unos principios tengan más peso que otros, porque cada situación es particular.
Lo &lt;strong&gt;primero&lt;/strong&gt; es &lt;strong&gt;evaluar&lt;/strong&gt; la situación, ponernos en la piel de los stakeholders y usuarios para conocer
su realidad. También es importante conocer la &lt;strong&gt;historia&lt;/strong&gt; del producto, las manos por las que ha pasado,
el impacto que tiene en la vida de las personas… De los primeros días de toma de contacto conseguimos conocer cuáles son las expectativas de los stakeholders, los riesgos y las metas,
sobre todo en el corto plazo. En este post no hablaré de las jornadas de &lt;em&gt;inception&lt;/em&gt; del proyecto.
Uno de los mayores objetivos es hacer equipo, crear un ambiente de colaboración sana con todas las
personas que intervienen en el desarrollo del producto.&lt;/p&gt;

&lt;p&gt;Al ser código legacy es imposible hacer estimaciones sobre las tareas porque uno no tiene ninguna
tarea que sirva de referencia para hacer estimaciones, por lo cual no merece la pena planificar una
iteración con unos compromisos de entrega. Lo que hacemos es montar un kanban con las tareas que
son más prioritarias como para tener trabajo para un puñado de días. Para eso evaluamos el
impacto en el negocio y la supuesta facilidad de la tarea, buscando aquellas tareas que nos den
el mayor beneficio con el mínimo esfuerzo.&lt;/p&gt;

&lt;p&gt;La dificultad de esta primera fase es el aterrizaje en el caos y la incertidumbre. Las recetas de los manuales y los libros no encajarán en nuestro contexto. Habrá que tirar de sentido común, de preguntarnos el &lt;em&gt;por qué&lt;/em&gt; y &lt;em&gt;para qué&lt;/em&gt; de la estrategia que vayamos a seguir.&lt;/p&gt;

&lt;p&gt;Los objetivos de esta primera etapa son:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;No introducir más bugs. Tener máximo cuidado de no romper nada.
    &lt;ul&gt;
      &lt;li&gt;Al principio no podremos aplicar la regla del Boy Scout todo lo que nos gustaría porque desconocemos el nivel de acoplamiento del código y queremos evitar romperlo a toda costa. Hay que conformarse con pequeños cambios de impacto muy localizado y hacer
   anotaciones y comentarios para más adelante.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Empezar a cartografiar esa gran masa de código
    &lt;ul&gt;
      &lt;li&gt;Conocer cómo de grande es el código.&lt;/li&gt;
      &lt;li&gt;Meter trazas para averiguar qué partes del código están siendo usadas y cuáles no. El objetivo es borrar código no usado en las próximas fases.&lt;/li&gt;
      &lt;li&gt;Averiguar en qué zonas hay mayor densidad de bugs.&lt;/li&gt;
      &lt;li&gt;Anotar los puntos donde observemos mayores dificultades, ya sea de comprensión, de testing…&lt;/li&gt;
      &lt;li&gt;Anotar deuda técnica que encontremos.&lt;/li&gt;
      &lt;li&gt;Anotar deuda tećnica que vayamos introduciendo.&lt;/li&gt;
      &lt;li&gt;Averiguar cuáles son las funcionalidades de mayor valor y cómo es su código.&lt;/li&gt;
      &lt;li&gt;Averiguar si hay zonas útiles pero que no requieren mantenimiento, que llevan mucho tiempo sin tocarse.&lt;/li&gt;
      &lt;li&gt;Escanear con herramientas de análisis de código estático para que nos ayuden.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Conocer la infraestructura y los ciclos de puesta en producción&lt;/li&gt;
  &lt;li&gt;Documentar. Los proyectos no tienen documentación o está tan obsoleta que es inútil.
    &lt;ul&gt;
      &lt;li&gt;Todo lo que echemos en falta para montar el entorno de desarrollo local.&lt;/li&gt;
      &lt;li&gt;Todo lo que haga falta para desplegar.&lt;/li&gt;
      &lt;li&gt;La arquitectura del proyecto y las convenciones, si las hubiera.&lt;/li&gt;
      &lt;li&gt;Añadir comentarios en el código que nos ha costado tiempo entender pero que no podemos cambiar por miedo a romper cosas. Los comentarios en el código son muy útiles en estos casos. Se pueden borrar cuando adquiramos la capacidad de hacer cambios en el código con seguridad de no romper nada.&lt;/li&gt;
      &lt;li&gt;Describir cómo se prueba a mano la aplicación para poder hacer pruebas de regresión manual. Algo sencillo como una hoja de cálculo es suficiente como plan de
   pruebas hasta que vayamos pudiendo automatizar. No hay que hacerlo para todo sino
   para los casos que sean menos intuitivos o más relevantes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Ganar la confianza de los stakeholders mostrando resultados visibles a corto plazo
    &lt;ul&gt;
      &lt;li&gt;Si llevaba tiempo sin haber novedades en las releases, lo primero es demostrar que estamos aquí para trabajar por ellos. Evitar que aumente la inestabilidad del sistema por causa de defectos, es justamente lo que merma la confianza.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En definitiva se trata de adquirir conocimiento a nivel global sobre las personas, el producto,
el código y la infraestructura. Con este conocimiento, en las siguientes etapas ya podremos hacer
mayores cambios en el código y ayudar a planificar releases con conocimiento del tiempo estimado
de las tareas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arreglar bugs&lt;/strong&gt; que lleven tiempo reportados es una de las formas que tenemos de empezar a acercarnos al código legado. Se priorizan y se ponen en el kanban. La investigación inicial de esos bugs no tiene por qué ser en pares pero luego la resolución sí. Es especialmente importante hacer pair programming ahora que el código es tan sumamente delicado. Otra opción es dedicarse de tareas que aparentemente sean sencillas como cambiar textos o actualizar alguna librería que haya quedado obsoleta. Conviene medir el tiempo que tardamos en realizar estas pequeñas tareas para que todo el equipo vaya asimilando lo que cuesta cada cosa.&lt;/p&gt;

&lt;p&gt;Cuando nos enfrentamos a código legado y queremos dejarlo mejor de lo que lo encontramos, hay que medir muy bien cuánto lo queremos mejorar porque pasado un límite puede que la inversión no merezca la pena. Cuidado con el &lt;strong&gt;refactor&lt;/strong&gt;. En la fase inicial puede que incluso desconozcamos si el código que estamos tocando es relevante para el negocio. Tal vez es una funcionalidad que no se usa. Si este fuera el caso, el refactor sería tirar dinero a la basura porque ni la mejora del código aporta ni el conocimiento que vamos a adquirir nos va a servir. Por otro lado modificar  código que tiene muy poco ratio de cambio tampoco tiene un gran retorno de inversión. Nos puede ayudar a entender el negocio pero es preferible borrar los cambios después de haberlos hecho antes que arriesgarnos a romper algo que está funcionando bien. El mejor código para refactorizar es el que nos está impidiendo realizar la tarea en curso. Y lo modificamos lo mínimo necesario para resolver la tarea. En ningún caso dejamos el código peor de lo que está, siempre lo mejoramos aunque sea introduciendo una variable explicativa. Lo que no perdería de vista es que en esta fase inicial,
&lt;strong&gt;no buscamos explorar en profundo sino en ancho&lt;/strong&gt;. Buscamos hacernos con una idea global que después nos permita tomar &lt;strong&gt;mejores decisiones sobre la economía del software&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Lo deseable es construir una base de conocimiento apoyada de unas métricas que nos permitan llegar a
ese día en que podamos ser predecibles y dar información de costes fiable para una planificación que sirva al negocio.&lt;/p&gt;

&lt;p&gt;Una de las dificultades será la incomodidad que nos puede generar estar haciendo labores que no son
nuestra especialidad. Puede ser que no nos sintamos útiles haciendo tareas de análisis,
de documentación, pruebas manuales o hablar con stakeholders… cualquier cosa que no sea programar.
Pero &lt;strong&gt;nuestro valor más fuerte no está en el código&lt;/strong&gt; que escribimos. Está en maximizar el impacto del producto y minimizar su coste. Las mejores prácticas de ingeniería no sirven si le dan la espalda
al propósito del proyecto. Las dos cosas van unidas.&lt;/p&gt;

&lt;p&gt;Un proyecto que lleva 5 años en marcha pasando por diferentes equipos no va a ser domado en menos de un año ni en dos. Hay que tener paciencia y atacar de forma estratégica, dando diferente peso a los principios en función del contexto y rediseñando las prácticas. Poniendo la energía en donde produzca mejor resultado. Nunca hay dos proyectos iguales.&lt;/p&gt;
</description>
          <pubDate>2017-07-24T13:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/07/aterrizando-en-proyecto-con-legado</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/07/aterrizando-en-proyecto-con-legado</guid>
        </item>
      
    
      
        <item>
          <title>Segundo curso abierto de TDD del año en Barcelona</title>
          <description>&lt;p&gt;El mes pasado &lt;a href=&quot;https://twitter.com/luisrovirosa?lang=en&quot;&gt;Luis&lt;/a&gt; y yo hicimos un curso abierto de TDD en Barcelona. Fue una edición muy interesante en la que probamos algunos cambios en el contenido del curso, y en la que participaron algunos conocidos de la comunidad de Barcelona.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_tdd_mayo_2017.jpg&quot; alt=&quot;curso abierto de TDD deMayo 2017 en Barcelona&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En las últimas ediciones del curso, nos habíamos dado cuenta de que el ejercicio de &lt;a href=&quot;http://coding-is-like-cooking.info/2013/04/outside-in-development-with-double-loop-tdd/&quot;&gt;outside-in TDD&lt;/a&gt;, la &lt;a href=&quot;https://github.com/sandromancuso/Bank-kata&quot;&gt;Bank Kata&lt;/a&gt;, que hacíamos el segundo día le estaba resultando muy difícil a los alumnos. En outside-in TDD se usan los dobles de prueba como herramienta de &lt;a href=&quot;http://garajeando.blogspot.com.es/2015/08/contract-tests-for-interfaces.html&quot;&gt;diseño y exploración de interfaces&lt;/a&gt;, lo cual resulta muy complicado cuando una persona aún no ha acabado de entenderlos y manejarlos con soltura.&lt;/p&gt;

&lt;p&gt;Esta dificultad estaba suponiendo un obstáculo para que acabaran de entender los dobles de prueba. Por ese motivo, decidimos mover el ejercicio de outside-in TDD al principio de un curso más avanzado de TDD que estamos preparando, y hacer otro ejercicio más sencillo en su lugar que les ayudase a asimilar mejor los conceptos.&lt;/p&gt;

&lt;p&gt;El nuevo ejercicio que elegimos fue la &lt;a href=&quot;http://simcap.github.io/coffeemachine/&quot;&gt;Coffee Machine Kata&lt;/a&gt;. Es una kata muy interesante que ya había probado en un &lt;a href=&quot;https://www.meetup.com/Barcelona-Software-Craftsmanship/events/232878806/&quot;&gt;dojo de SCBCN&lt;/a&gt;. Creemos que nuestro experimento funcionó bastante bien. Usando esta nueva kata se entiende de forma más gradual y menos traumática cómo y cuándo aplicar cada tipo de doble de prueba. Acabamos muy satisfechos con el resultado de nuestro pequeño experimento y el feedback que recibimos.&lt;/p&gt;

&lt;p&gt;Esta edición fue la segunda que hacíamos en lo que va de año, y hubo más gente que en la &lt;a href=&quot;/2017/01/curso-abierto-tdd-en-bcn&quot;&gt;edición anterior&lt;/a&gt;. Esto se debió en gran parte a que vinieron desde Zaragoza cuatro personas que trabajan en &lt;a href=&quot;http://www.inycom.es/&quot;&gt;Inycom&lt;/a&gt;. Muchas gracias por confiar en nosotros.&lt;/p&gt;

&lt;p&gt;También nos gustaría darle las gracias a todos los asistentes por su entrega y ganas de aprender. Finalmente, agradecer a &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento&lt;/a&gt;, especialmente a &lt;a href=&quot;https://twitter.com/rojoangel&quot;&gt;Ángel Rojo&lt;/a&gt; que nos hayan acogido de nuevo en sus oficinas y toda la ayuda que nos prestaron, y a nuestra compañera &lt;a href=&quot;/2017/05/dacil-casanova-se-une-a-codesai&quot;&gt;Dácil&lt;/a&gt; por organizarlo todo.&lt;/p&gt;
</description>
          <pubDate>2017-06-26T16:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/06/segundo-curso-abierto-bcn</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/06/segundo-curso-abierto-bcn</guid>
        </item>
      
    
      
        <item>
          <title>Testing Om components with cljs-react-test</title>
          <description>&lt;p&gt;I’m working for &lt;a href=&quot;http://www.greenpowermonitor.com/&quot;&gt;Green Power Monitor&lt;/a&gt; which is a company based in Barcelona specialized in monitoring renewable energy power plants and with clients all over the world.&lt;/p&gt;

&lt;p&gt;We’re developing a new application to monitor and manage renewable energy portfolios. I’m part of the front-end team. We’re working on a challenging SPA that includes a large quantity of data visualization and which should present that data in an UI that is polished and easy to look at. We are using &lt;i&gt;ClojureScript&lt;/i&gt; with &lt;a href=&quot;https://github.com/omcljs/om&quot;&gt;Om&lt;/a&gt; (a &lt;i&gt;ClojureScript&lt;/i&gt; interface to &lt;i&gt;React&lt;/i&gt;) which are helping us be very productive.&lt;/p&gt;

&lt;p&gt;I’d like to show an example in which we are testing an &lt;i&gt;Om&lt;/i&gt; component that is used to select a command from several options, such as, loading stored filtering and grouping criteria for alerts (views), saving the current view, deleting an already saved view or going back to the default view.&lt;/p&gt;

&lt;p&gt;This control will send a different message through a &lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt; channel depending on the selected command. This is the behavior we are going to test in this example, that the right message is sent through the channel for each selected command.  We try to write all our components following this guideline of communicating with the rest of the application by sending data through &lt;i&gt;core.async&lt;/i&gt; channels. Using channels makes testing much easier because the control doesn’t know anything about its context&lt;/p&gt;

&lt;p&gt;We’re using &lt;a href=&quot;https://github.com/bensu/cljs-react-test&quot;&gt;cljs-react-test&lt;/a&gt; to test these &lt;i&gt;Om&lt;/i&gt; components as a black box. &lt;i&gt;cljs-react-test&lt;/i&gt; is a &lt;i&gt;ClojureScript&lt;/i&gt; wrapper around &lt;a href=&quot;https://facebook.github.io/react/docs/test-utils.html&quot;&gt;Reacts Test Utilities&lt;/a&gt; which provides functions that allow us to mount and unmount controls in test fixtures, and interact with controls simulating events.&lt;/p&gt;

&lt;p&gt;This is the code of the test:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/095fecc60c31a893c6dc182ae518605d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We start by creating a var where we’ll put a DOM object that will act as container for our application, &lt;i&gt;c&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;We use a fixture function that creates this container before each test and tears down &lt;i&gt;React&lt;/i&gt;’s rendering tree, after each test. Notice that the fixture uses the &lt;a href=&quot;https://cljs.github.io/api/cljs.test/async&quot;&gt;async macro&lt;/a&gt; so it can be used for asynchronous tests. If your tests are not asynchronous, use the simpler fixture example that appears in &lt;a href=&quot;https://github.com/bensu/cljs-react-test&quot;&gt;cljs-react-test documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All the tests follow this structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up the initial state in an atom, &lt;i&gt;app-state&lt;/i&gt;. This atom contains the data that will be passed to the control.&lt;/li&gt;
&lt;li&gt;Mounting the Om root on the container. Notice that the &lt;i&gt;combobox&lt;/i&gt; is already expanded to save a click.&lt;/li&gt;
&lt;li&gt;Declaring what we expect to receive from the &lt;i&gt;commands-channel&lt;/i&gt; using &lt;i&gt;expect-async-message&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;Finally, selecting the option we want from the &lt;i&gt;combobox&lt;/i&gt;, and clicking on it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;i&gt;expect-async-message&lt;/i&gt; is one of several functions we’re using to assert what to receive through  &lt;i&gt;core.async&lt;/i&gt; channels:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a39f5fbec6ab0ee0c6f8db68e87a552c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The good thing about this kind of &lt;a href=&quot;https://en.wikipedia.org/wiki/Black-box_testing&quot;&gt;black-box tests&lt;/a&gt; is that they interact with controls as the user would do it, so the tests know nearly nothing about how the control is implemented.&amp;lt;/div&amp;gt;&lt;/p&gt;
</description>
          <pubDate>2017-06-23T12:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/06/testing-om-components</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/06/testing-om-components</guid>
        </item>
      
    
      
        <item>
          <title>¿Null, vacío o exception?</title>
          <description>&lt;p&gt;Siempre que imparto una formación aprendo de los participantes. Cuando surgen dudas y debates en el grupo, se abre un espacio ideal para el aprendizaje. Los últimos dos días hemos tenido la suerte de estar con el equipo de &lt;a href=&quot;http://www.zooplus.es/&quot;&gt;Zooplus&lt;/a&gt; en Madrid practicando TDD y hablando mucho de diseño de software.&lt;/p&gt;

&lt;p&gt;Durante la &lt;a href=&quot;http://thecleancoder.blogspot.com.es/2010/10/craftsman-62-dark-path.html&quot;&gt;WordWrap kata&lt;/a&gt; algunas personas plantearon
casos límite muy interesantes. La firma de la función es esta:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; public String wrap(String text, int columns){...}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dado un texto de entrada y un ancho de columna, el texto de salida será
el de entrada, con tantos saltos de línea añadidos como hagan falta 
para que todas las líneas tengan una longitud menor o igual al número
de columnas.&lt;/p&gt;

&lt;p&gt;¿Cómo debería comportarse cuando el primer argumento sea &lt;strong&gt;null&lt;/strong&gt;? ¿y si el primer argumento es texto y 
 el segundo es &lt;strong&gt;cero&lt;/strong&gt;? ¿y un &lt;strong&gt;número negativo&lt;/strong&gt;? y… ¿qué pasa si el 
 primer argumento es &lt;strong&gt;null&lt;/strong&gt; y el segundo es un &lt;strong&gt;número negativo&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Son decisiones de comportamiento que hay que tomar. En la conversación
había opiniones muy dispares y no llegamos a ningún consenso. El motivo
creo que se debe a la falta de principios sobre los que sostener 
nuestras hipótesis, lo cual hace que parezca una cuestión de gustos 
algo irracional. Si consensuamos unos principios es más fácil decidir
cuál es el comportamiento más adecuado.&lt;/p&gt;

&lt;p&gt;Para mí &lt;strong&gt;el principio más importante&lt;/strong&gt; de todos es el de 
&lt;strong&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/Principio_de_la_M%C3%ADnima_Sorpresa&quot;&gt;menor sorpresa&lt;/a&gt;&lt;/strong&gt;, no me gusta que el 
código me sorprenda. 
Pero además de este necesito otros para tomar estas decisiones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Simplicidad&lt;/li&gt;
  &lt;li&gt;Responsabilidad única&lt;/li&gt;
  &lt;li&gt;Consistencia lógica&lt;/li&gt;
  &lt;li&gt;Resiliencia&lt;/li&gt;
  &lt;li&gt;Evitar propagación de nulos&lt;/li&gt;
  &lt;li&gt;Evitar propagación de excepciones de las que nadie se puede recuperar&lt;/li&gt;
  &lt;li&gt;Evitar números mágicos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para mí que el texto sea &lt;em&gt;null&lt;/em&gt; es lo mismo que si llega vacío, es ausencia
de texto y por tanto veo lógico que la respuesta sea texto vacío. No 
devolvería &lt;em&gt;null&lt;/em&gt; porque la experiencia me dice que los nulos dan mucha 
guerra. Obligan al llamador a defenderse del nulo, propagando la molestia
por todo el código hasta que alguien acabe con ella por algún lado. 
Es extraño que venga &lt;em&gt;null&lt;/em&gt; pero no quiero dar a esta función
de bajo nivel dos responsabilidades, la de validación y la propia de
wrap que ya tiene. Si quisiera darle la responsabilidad de validación
podría lanzar una excepción en este punto. Pero el lanzamiento de 
excepciones también se progaga por el código como los nulos e incluso
peor.&lt;/p&gt;

&lt;p&gt;Aquí entra en juego la experiencia que uno tiene enfrentandose a 
escenarios de ejecución donde ese texto llega a null. Y en la mía estos
 casos son realmente casos límite. Si he programado todo con TDD desde
 afuera hacia dentro, habiendo programado primero el llamador de esta
 función, yo ya sé que mi código no genera ese null a propósito en ningún
 caso. Por tanto ha de venir de algún caso límite que no he tenido en 
 cuenta. No puede venir de ningún &lt;em&gt;“happy path”&lt;/em&gt; porque esos los tengo
 todos testados. Es muy probable que ese caso límite venga de algún
 campo de la GUI que se quedó vacío o se le dió un uso inesperado. 
 Si este es el caso, devolver null o lanzar una 
  excepción provocará muy posiblemente que el programa se interrumpa o
  el usuario vea un error extraño en pantalla. Sin embargo, si devuelvo
  un texto vacío eso no ocurrirá. Igualmente no va a arrojar ningún 
  resultado pero no dará error. En mi opinión estamos ganando en 
  resiliencia del software. 
  Puesto que soy capaz de darle un sentido lógico a la entrada de un 
  texto nulo y responder con vacío sin causarle sorpresa al lector del
  código, esta es mi opción preferida. Se comentaba como alternativa 
  que la función podría devolver un &lt;em&gt;“Optional”&lt;/em&gt; para posponer la
   decisión o delegarla al llamador. De alguna manera un tipo
    opcional sirve como &lt;a href=&quot;https://sourcemaking.com/design_patterns/null_object&quot;&gt;patrón null&lt;/a&gt; pero al igual que antes
     prefiero atajar la situación y frenar la posibilidad de que la
      burbuja polucione hasta muy arriba.&lt;/p&gt;

&lt;p&gt;Ahora supongamos que el texto es una cadena no vacía pero que el número
  de columnas es cero o negativo. No se me había ocurrido nunca este
  caso. Si no hay ningún tipo de tratamiento de cero y negativos
  se provocaría una excepción, seguramente de índices, interrumpiendo
  el programa. Ante cero o negativo no se me ocurre ninguna
  respuesta lógica que pueda dar para salir del paso. Verdaderamente 
  no sé cómo procesarlo y solo me queda detener la ejecución.
  ¿Entonces chequearía el parámetro para lanzar una excepción de
  validación? Si se trata de mi código y quien lo va a invocar somos
   nosotros del equipo de desarollo no lo haría. Porque no quiero 
   validaciones en este nivel sino que la función tenga 
   la responsabilidad de partir el texto y nada más. Cuando se produzca
   la excepción no controlada tendremos acceso a toda la traza y será
   fácil entenderla. Lo que sí haría es pegarle una revisión al código
   que va a llamar a esta función para estudiar si allí conviene validar
   o evitar que eso se produzca. La mejor solución que se me ocurre
   para quitarnos toda esta problemática es dejar de usar tipos 
   primitivos en la firma de la función. A menudo &lt;strong&gt;pecamos de polucionar
   nuestro núcleo de negocio con primitivos&lt;/strong&gt; que carecen de la 
   expresividad que necesitamos. La solución sería una firma como esta:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   public Text wrap(Text text, ColumnWidth width){...}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si el tipo &lt;em&gt;Text&lt;/em&gt; implementa algún tipo de &lt;a href=&quot;https://sourcemaking.com/design_patterns/null_object&quot;&gt;patrón vacío o null&lt;/a&gt; nos
   quitamos uno de los problemas. Si el tipo &lt;em&gt;ColumnWidth&lt;/em&gt; sólo admite
   números positivos nos quitamos el otro. Los primitivos son 
   imprescindibles en los límites de nuestro dominio, para interactuar
   con el exterior, pero dentro de nuestro dominio deberiamos usar 
   nuestros propios tipos dotados de una semántica clara y sin lugar
   a errores.&lt;/p&gt;

&lt;p&gt;Por otra parte si la función es parte de una librería de propósito
   general que voy a exponer al mundo, preferiría dejar los primitivos
   y sí que lanzaría una excepción de
   validación que indicase claramente que ese parámetro no puede ser
   cero ni negativo. A quien usa una librería le va a resultar muchísimo
   más fácil darse cuenta que se está equivocando al invocarla 
   si somos explícitos sobre el error. StackOverflow está lleno de gente
   preguntando por mensajes de error en librerías y frameworks que no 
   son bugs sino un uso erróneo de los mismos, que no fue anticipado
   por los autores.&lt;/p&gt;

&lt;p&gt;Por regla general, &lt;strong&gt;sólamente uso excepciones cuando soy incapaz de seguir 
  adelante con la ejecución&lt;/strong&gt;. Y no veo diferencia entre el cero y 
  los negativos. Algunas personas comentaron que se podía entender que
  el cero significa “no partir lineas” pero yo evito codificar
   comportamientos con números mágicos. Por eso descarto esta
  opción, ya que obliga al llamador a conocer demasiados detalles de
  implementación.&lt;/p&gt;

&lt;p&gt;¿Y si el texto es null y el número de columnas negativo?&lt;/p&gt;

&lt;p&gt;Si he decidido no lanzar excepción ante números negativos la función
  devolverá vacío sin más. Si he decidido controlarlo, entonces por
   consistencia, cuando el número es cero o negativo lanzaré una 
   excepción que diga que no se puede interpretar ese valor por más
    que el texto sea nulo.&lt;/p&gt;

&lt;p&gt;¿Estamos de acuerdo en estos principios? Si no te gustan tengo 
    otros :-)&lt;/p&gt;

</description>
          <pubDate>2017-06-11T10:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/06/null_empty_exception</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/06/null_empty_exception</guid>
        </item>
      
    
      
        <item>
          <title>Testing tricks for react-redux</title>
          <description>&lt;p&gt;We are using &lt;a href=&quot;https://github.com/airbnb/enzyme&quot;&gt;enzyme&lt;/a&gt; and &lt;a href=&quot;https://github.com/tmpvar/jsdom&quot;&gt;jsdom&lt;/a&gt; to write both, integration and unit tests for react-redux apps. Although &lt;a href=&quot;https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md&quot;&gt;enzyme’s shallow&lt;/a&gt; is very convenient totest components in isolation, the truth is that often those components have children that need to be rendered in order for the parent to do something meaningful so we end up using &lt;a href=&quot;https://github.com/airbnb/enzyme/blob/master/docs/api/mount.md&quot;&gt;enzyme’s mount&lt;/a&gt; most of the time.&lt;/p&gt;

&lt;p&gt;When there is no logic in the component, I want to test the integration with actions, reducers and the store. Otherwise tests don’t provide me with the sense of safety that I am looking for. The top one difficulty when integrating these pieces is the &lt;strong&gt;asynchronous&lt;/strong&gt; nature of redux - tests finish before the expected behavior occurs.&lt;/p&gt;

&lt;p&gt;Using the &lt;em&gt;“done()”&lt;/em&gt; parameter provided by mocha or jest plus &lt;em&gt;“setTimeout()”&lt;/em&gt; in the test is not a reliable combination. The way I do it is spying on certain component or subscribing to changes in the store in order to call &lt;em&gt;“done()”&lt;/em&gt;, as explained in previous posts. But if you call &lt;em&gt;“done()”&lt;/em&gt; before the expectation, it finishes and no expectation is executed. On the other hand, if the expectation fails &lt;em&gt;“done()”&lt;/em&gt; is never called and the test fails with a timeout.&lt;/p&gt;

&lt;p&gt;This is a helper function to work around the issue:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c87cb0e6224d6656772e83b03ab1a916.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;where expectation is a callback. That could be used like this:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/285c0fede6700a6fba2eb8eee0dcd9cb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Things start to get messy if the store is updated several times during that test, as the listener will be invoked when the data is not in the expected state yet. When that happens is time to re-think the design of the system and strive for simpler options.&lt;/p&gt;

&lt;p&gt;Sometimes asynchronous tests fail with a timeout because there is some unhandled promise rejection. The console prints out this warning:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; (node:9040) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 97): Error: ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s possible and very useful to configure node so that when rejection happens the execution stops printing the stack trace:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ca67efbc3a67b1aa7ea5b960a5e7322b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Invoke the function before running the tests.&lt;/p&gt;

&lt;p&gt;Apart from asynchronous tests, other issue we had was &lt;strong&gt;testing changes in the URL, in the browser history&lt;/strong&gt;. We have a component that changes the query string when submitting a form. It does not post the form. The same component parses the URL every time it changes or when it loads looking for changes in the query string in order to make requests to the server. The query string serves as a filter. After spending sometime, I didn’t know how to simulate changes in the location with jsdom. All I got were security exceptions so changing the browser history was not a working option unfortunately.&lt;/p&gt;

&lt;p&gt;To work around this, given we are using &lt;a href=&quot;https://github.com/reactjs/react-router-redux&quot;&gt;react-router-redux&lt;/a&gt; and enzyme’s mount, we connect a stub router to the component explicitly as shown below. Basically react-router-redux connects the router with the component for you by adding a &lt;em&gt;“routing”&lt;/em&gt; property to the component that maps to &lt;em&gt;“state.routing”&lt;/em&gt; thus causing component’s _ “componentWillReceiveProps”_ to be executed as the router handles a change in the location. In the tests, I have to make this mapping explicitly because the router does not work with jsdom as far as I have researched. The code below will be part of the test file:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/4b724448261795a9b6bd63c725e53bb0.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The factory - production code:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/b82add3db528a277865218a6dc7b27df.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;It’s quite tricky to be honest but it exercises the production code exactly as running the application manually. The code snippet in the test file is not complete as you can imagine, only the relevant lines appear.&lt;/p&gt;

&lt;p&gt;Another difficulty we run into recently was &lt;strong&gt;simulating a scroll event&lt;/strong&gt;. At the time of this writing, apparently jsdom does not 
implement a way to simulate scrolling so calling &lt;em&gt;simulate(‘scroll’)&lt;/em&gt; does nothing. To work around this, I invoke the event handler directly as it’s a public method on the component. Well, it’s public because ES6 classes don’t implement private methods. Instance methods can be accessed through enzyme’s _“instance()”, method on the wrapper object. However this method works only on the parent component. If you want to access a child component it gets more tricky. It could be the case of a component that should be child of a draggable in order for drag &amp;amp; drop to work:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/41e67d8d847143ead2dd3fdfcd7fd46e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The instance of the component under test is the first node.&lt;/p&gt;
</description>
          <pubDate>2017-06-08T16:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/06/testing-hacks-react-redux</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/06/testing-hacks-react-redux</guid>
        </item>
      
    
      
        <item>
          <title>Eventazo Startupero en Zaragoza, ahí estuvimos.</title>
          <description>&lt;p&gt;Con un poco de retraso llega este post-celebración del paso de Codesai por el SOSZ en Zaragoza.&lt;/p&gt;

&lt;p&gt;Yo, personalmente, nunca había tenido la oportunidad de acudir al &lt;a href=&quot;https://www.cachirulovalley.com/sosz17&quot;&gt;SOSZ&lt;/a&gt; y este año lo tenía marcado con un corazón en el calendario.
Me llamaba la atención por varias razones:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;no era en Madrid, lo que últimamente creo que es algo a agredecer y apoyar,&lt;/li&gt;
  &lt;li&gt;era sobre Startups, un sector con el que queremos desde Codesai tener más relación, y&lt;/li&gt;
  &lt;li&gt;está organizado por la muchachada aragonesa, que ya solo con eso había que ir a verlo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Así que nos animamos &lt;a href=&quot;https://twitter.com/AlfredoCasado&quot;&gt;Alfredo Casado&lt;/a&gt; y yo a ir a conocer tan prometedor evento.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sosz17_openspace.jpg&quot; alt=&quot;Pablo Jimeno facilitando el Open Space&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tras un viernes noche de bienvenida que no defraudó en absoluto, comenzó el sábado bien temprano, un Open Space facilitado por Pablo Jimeno de manera a mi parecer fantástica. La justa proporción entre humor y trance para ponernos a todos a punto para la desconferencia.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sosz17_tablon.jpg&quot; alt=&quot;Tablon Open Space&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Las propuesta de sesiones fue muy variada: Temas como financiación, crear empleo, tarifas en tecnología, la España rural, … , dándonos una visión que creemos bastante realista de las necesidades del panorama actual.&lt;/p&gt;

&lt;p&gt;Las sesiones fueron muy animadas en su mayoría, aunque algunas de ellas hasta demasiado. Salas masificadas, hacían que no se pudiese llegar a profundizar y concluir el tema como debería.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sosz17_sesion_conciliar.jpg&quot; alt=&quot;Participando en la sesion de conciliar&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pablo Jimeno en su sesión hizo un gran intento de mejorar este problema que estábamos teniendo con la participación y yo creo que le salió muy bien. El tema, la conciliación familiar en este trabajo que tenemos tan absorbente, fue de las que más me tocó y me gustaría dedicarle un artículo específico.
Si los que tenemos familia podemos ir a eventos, es porque alguien se está haciendo cargo en ese momento de nuestras obligaciones y hay que agradecerlo.&lt;/p&gt;

&lt;p&gt;Otras sesión interesante, fue la que propusimos Alfredo y yo: “El equipo tecnológico, ¿mejor dentro, o fuera?”.
Fue una conversación muy animada, dónde estuvimos de acuerdo en este resumen ejecutivo: Cuando estás al principio, necesitas que alguien te guíe, cuando ya estás más lanzado, es importante que ese conocimiento quede en la empresa.&lt;/p&gt;

&lt;p&gt;Y también a destacar las sesiones: “Emprender en la España (rural) vacía” y “Creación de empleo de las Startups en comparación con la gran empresa”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sosz17_one_session.jpg&quot; alt=&quot;Una sesión muy masificada&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Después del evento fuimos a La Jamonería, lugar de culto de los maños, que no defraudó en absoluto. Además tuve ocasión de hablar un buen rato con el dueño, Félix, que me hizo un pequeño resumen de su interesante historia de emprendedor atípico.&lt;/p&gt;

&lt;p&gt;Y así cerramos uno de lo eventos más interesantes a los que he asistido últimamente.&lt;/p&gt;

&lt;p&gt;Me llevo un gran descubrimiento: el hecho de conocer a muchos participantes, a priori me hizo pensar que íbamos a hablar de temas técnicos. Pero fue todo lo contrario, solo se habló de negocio, haciendo visible una faceta que no había visto hasta ahora.&lt;/p&gt;
</description>
          <pubDate>2017-05-25T08:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/05/estuvimos-en-sosz-zaragoza</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/05/estuvimos-en-sosz-zaragoza</guid>
        </item>
      
    
      
        <item>
          <title>Dácil Casanova se une a Codesai</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/codesai_at_full.jpg&quot; alt=&quot;The Codesai Team&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A pesar de que se constituye en 2015, Codesai es para mí una vieja conocida. He atendido
expectante a su gestación en estos trece años que hace que conozco a Carlos Blé. Existen muchas
historias antes de su nacimiento, muchas pruebas, muchos sueños y muchas ganas de hacer las
cosas de una forma diferente.&lt;/p&gt;

&lt;p&gt;Por eso, aunque mi incorporación oficial se produce ahora, siento que hace mucho que nos
acompañamos.&lt;/p&gt;

&lt;p&gt;Lo que sí es cierto es que no esperaba en absoluto la calidad humana del equipo que conforma
Codesai. Bueno, no es que no lo esperara en absoluto, a algunos de los chicos ya los conocía y
sabía de sus cualidades personales pero no había tenido ocasión de ver cómo se desenvolvían
laboralmente. Este año he podido asistir a una de las reuniones en las que se convoca a todo el
equipo para debatir acerca de a dónde vamos, cómo vamos y qué esperamos. Los internamente
famosos “Flejesai” Así pues, los días 18 y 19 de marzo los pasamos recluidos en una sala
acondicionada para ello en un hotel de Madrid. Fue muy intenso pero muy alentador, es grandioso
ser consciente de que Codesai no busca maximizar el beneficio sino maximizar el bienestar y más
grandioso si cabe es ver cómo el equipo rema a una, cómo la empresa no es más que el mero
reflejo de aquellos que la componen. Se han tomado muchas decisiones, la mayoría se revisará en
el próximo Flejesai, algunas pasarán a formar parte de nuestro modus operandis y otras se
desecharán. No existe miedo al cambio, mejor dicho, sí que existe pero simplemente se le hace
frente. Creo que la vida en sí misma se ha encargado de gritarnos lo importante que es ser versátil
pero nos empeñamos en no escucharla, en meterle calzador a todo, en evitar ser muy reactivo.&lt;/p&gt;

&lt;p&gt;Personalmente, ha sido de las experiencias más enriquecedoras que he vivido en un trabajo. Ha
supuesto una ruptura total de esquemas. Mi educación como economista no me permitía ver a la
persona jurídica como una extensión de la física, los objetivos de la primera no podían ser
expresados en algo diferente a unidades monetarias. Ahora empiezo a comprender que la entidad
mercantil puede llegar a ser un ente orgánico, con sus valores, sus principios y, en definitiva, con
su alma. Me ha ayudado mucho leer acerca de esto en el libro de &lt;a href=&quot;https://es.linkedin.com/in/frederic-laloux-108174&quot;&gt;F. Laloux&lt;/a&gt;, 
&lt;a href=&quot;http://www.reinventingorganizations.com/es.html&quot;&gt;Reinventar las organizaciones&lt;/a&gt;, pero lo que más me ha motivado, siento repetirme, ha sido la implicación de cada
una de las personas que dan vida a Codesai. Gracias a todos por este aporte de energía!!!&lt;/p&gt;

&lt;p&gt;Empezamos el camino&lt;/p&gt;
</description>
          <pubDate>2017-05-18T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/05/dacil-casanova-se-une-a-codesai</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/05/dacil-casanova-se-une-a-codesai</guid>
        </item>
      
    
      
        <item>
          <title>Manuel J. Tordesillas joins Codesai</title>
          <description>&lt;p&gt;It has already been two months since I had the opportunity to become a member of Codesai and I cannot express with words how happy and grateful I am after joining this incredible group.&lt;/p&gt;

&lt;p&gt;I have always considered myself as an optimist and nonconformist person, continuously looking ahead and being certain that there is something better out there for us programmers. When I found myself without the knowledge, practice and skill to lead a change from within the organisations I was working for, I decided to have a break to start building the skills required to take such a challenge in the future.&lt;/p&gt;

&lt;p&gt;Amongst all good practices, I consider testing a cornerstone for any good and sustainable development. To improve my testing skills, I contacted &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;Carlos&lt;/a&gt; to attend their TDD open course in Madrid. I had met him in the Agile Open Space 2013 in Tenerife where I was introduced to Agilism, Open Spaces and katas, being greatly impressed by his knowledge and humility.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/codesai_at_full.jpg&quot; alt=&quot;The Codesai Team&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After a few talks with Carlos, he offered me to join Codesai as an apprentice and I did not have to think twice about it, I had already decided from the moment he offered! I have to say, it feels like one of the best decisions I have taken in the last few years. Codesai is not only a company with developers that are well known by the community and the industry, we are a group of human beings with aligned purposes and goals that want to make both the world and the industry a better place.&lt;/p&gt;

&lt;p&gt;Following Codesai’s spirit of sharing knowledge and teaching, I am currently being mentored by &lt;a href=&quot;http://twitter.com/trikitrok&quot;&gt;Manu Rivero&lt;/a&gt;. We are having weekly sessions to explore concepts and practice skills that are essential for the craft. You can follow our progress at our github repos: &lt;a href=&quot;http://github.com/pair-of-ms&quot;&gt;Pair of M’s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I joined Codesai because I wanted to learn, I have learned many things already and so many are there waiting, still to be learned. However, I found more than knowledge, I found a group of great people that inspire me every single day.&lt;/p&gt;

&lt;p&gt;Thank you for letting me in! :)&lt;/p&gt;
</description>
          <pubDate>2017-04-13T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/mjtordesillas-joining</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/mjtordesillas-joining</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Velneo (VisualMS)</title>
          <description>&lt;p&gt;El pasado 7 y 8 de marzo de 2017 estuvimos &lt;a href=&quot;https://www.twitter.com/trikitok&quot;&gt;Manuel Rivero&lt;/a&gt; y yo, impartiendo un curso de JavaScript para la empresa &lt;a href=&quot;https://velneo.es/&quot;&gt;Velneo&lt;/a&gt;, en sus oficinas de Gijón. Estuvimos 10 personas tanto de Velneo, como de otras empresas del grupo.&lt;/p&gt;

&lt;p&gt;Este post no sería más que una nota de nuestro día a día, si no fuera porque el empujón definitivo para escribirlo vino de una noticia que salió esta semana. &lt;a href=&quot;https://visualms.com/&quot;&gt;VisualMS&lt;/a&gt; (el grupo al que pertenece Velneo) fue reconocida como el mejor lugar para trabajar de España, primer premio &lt;a href=&quot;https://bestplacetowork.com&quot;&gt;Best Place to Work 2017&lt;/a&gt;, en la categoría de empresas de 50 a 100 empleados.&lt;/p&gt;

&lt;p&gt;Y no nos extraña en absoluto, se nota que tienen una relación especial entre ellos, disfrutamos muchísimo ese par de días compartiendo tiempo y espacio con un grupo de personas fantástico.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/velneo_risas.jpg&quot; alt=&quot;algunos miembros equipo Velneo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;¿Qué es Velneo?
Pues con mis propias palabras. Velneo es un entorno para crear &lt;a href=&quot;https://en.wikipedia.org/wiki/Enterprise_resource_planning&quot;&gt;ERPs&lt;/a&gt;. Sus clientes son empresas de desarrollo que configuran, adaptan y amplian, el producto para un cliente final. Puede ser una fábrica, una administración o una compañía de seguros. Han visto que su punto más valorado es la comunicación en español y tienen una fuerte presencia tanto en nuestro país, como en Latinoamérica.&lt;/p&gt;

&lt;p&gt;Hablando ahora un poco del curso, fue interesante porque hicimos un contenido ajustado a sus necesidades basado en JavaScript ES5. Actualmente el motor que tienen integrado en el producto no soporta ES6, pero no vimos problema, pues en Codesai somos muy fan del patrón módulo o del patrón &lt;a href=&quot;https://martinfowler.com/bliki/FunctionAsObject.html&quot;&gt;Function As Object&lt;/a&gt;, por ejemplo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/velneo_manu.jpg&quot; alt=&quot;Manuel Rivero en Velneo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El curso fue una combinación de teoría y práctica en forma de katas usando TDD. Era un equipo que nunca lo había practicado y se notó que lo pasaron en grande, programando en parejas, pensando los ‘baby steps’, y consiguiendo unos verdes preciosos.&lt;/p&gt;

&lt;p&gt;La valoración del curso en general fue muy alta (nos pusieron un 9 de media, ¡gracias!), y además nos dieron un feedback muy valioso. A destacar nos comentaron que hubiesen sacado más chicha de las katas si el tema fuera más alineado con su negocio, pues tardaban demasiado en comprender lo que se quería conseguir. Usaremos este conocimiento sabiamente.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/velneo_antonio.jpeg&quot; alt=&quot;Antonio de la Torre en Velneo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hemos recopilado la bibliografía que usamos para crear el curso y que también sirve para ampliar conocimientos. Está disponible aquí: &lt;a href=&quot;https://gist.github.com/trikitrok/397026e37c930bc76e15ed8c818fd206&quot;&gt;Bibliografía del curso&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;También recopilamos &lt;a href=&quot;https://github.com/Codesai/js-ES5-best-practices&quot;&gt;todos los ejemplos que usamos en este repositorio de Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gracias a todo el equipo de Velneo por esta gran experiencia y esperamos coincidir pronto en otros proyectos.&lt;/p&gt;
</description>
          <pubDate>2017-04-12T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/estuvimos-en-velneo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/estuvimos-en-velneo</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Women Tech Makers Madrid</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/small_codesai_en_wtm.jpg&quot; alt=&quot;miembros de Codesai en WTMMadrid&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El equipo de Codesai asistió el pasado 11 de Marzo al &lt;a href=&quot;http://wtm.gdgmadrid.es/&quot;&gt;Women Tech Makers (WTM) Madrid 2017&lt;/a&gt;. Women Techmakers es una iniciativa liderada por Google, que se está expandiendo a un programa a nivel mundial. Con motivo del &lt;strong&gt;Día Internacional de la Mujer&lt;/strong&gt;, se promueven diferentes eventos alrededor del mundo con el objetivo de dar a conocer el trabajo y el conocimiento de las mujeres en el sector técnico.&lt;/p&gt;

&lt;p&gt;La organización del evento fue estupenda, estuvieron en todo momento pendientes de que todo estuviera perfecto y que no faltase de nada. ¡Muchas gracias!&lt;/p&gt;

&lt;p&gt;Hubo desayuno y almuerzo incluído, donde tuvimos desde churros con chocolate por la mañana, hasta una pequeña variedad de pequeños snacks a la hora de la comida.&lt;/p&gt;

&lt;p&gt;Destacar la gran participación que hubo en las charlas y el nivelazo en general. Tenemos grandes desarrollador@s en España….&lt;/p&gt;

&lt;p&gt;Asistimos a las siguientes charlas:&lt;/p&gt;

&lt;h3 id=&quot;big-data--data-science--por-qué-todo-el-mundo-habla-de-ellos&quot;&gt;BIG DATA &amp;amp; DATA SCIENCE : ¿POR QUÉ TODO EL MUNDO HABLA DE ELLOS?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/quierodata&quot;&gt;Inés Huertas&lt;/a&gt; nos desveló algunos de los secretos sobre Big Data, una de las disciplinas que más atención están levantando en los últimos años. La industria genera una inmensa cantidad de datos de todo tipo que los Data Scientists se encargan de preprocesar, modelar y validar. Una vez validados sus modelos, pueden encontrar patrones, realizar labores de predicción con un alto porcentaje de acierto o aplicar técnicas de machine learning. Optimizar la frecuencia del transporte público, descubrir nuevos segmentos de mercado o interceptar al consumidor antes de abandonar tu tienda online son algunos de los ejemplos de aplicaciones prácticas que descubrimos en la charla.&lt;/p&gt;

&lt;h3 id=&quot;el-despertar-de-la-zona-de-confort&quot;&gt;EL DESPERTAR DE LA ZONA DE CONFORT&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/LauraLacarra&quot;&gt;Laura Lacarra&lt;/a&gt;  se encargó de sacarnos de nuestra zona de confort con una charla muy divertida y con un mensaje con el que en Codesai nos sentimos muy identificados. Laura nos habló de lo peligrosa que es la zona de confort y lo que hace falta para salir de ella y seguir evolucionando como profesionales. También nos habló de la importancia de las comunidades a la hora de compartir conocimiento y de mejorar nuestra industria.&lt;/p&gt;

&lt;h3 id=&quot;cómo-me-he-reinventado-como-programadora-web-front-end-en-3-meses&quot;&gt;CÓMO ME HE REINVENTADO COMO PROGRAMADORA WEB FRONT-END EN 3 MESES&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/txutxina91&quot;&gt;Rocío Gómez&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/finuka&quot;&gt;Fina Pérez&lt;/a&gt; nos hablaron sobre el programa de &lt;a href=&quot;http://adalab.es/&quot;&gt;Adalab&lt;/a&gt;. Adalab es un proyecto que impulsa a mujeres jóvenes con dificultades de empleabilidad para que se conviertan en profesionales líderes del mundo digital. El programa consiste en dar una formación durante 3 meses sobre tecnologías front-end, seguida de unas prácticas en empresas para consolidar dichos conocimientos previamente adquiridos y así empezar a conseguir experiencia profesional. Durante los 3 meses, a cada alumna se le asigna una mentora que le guiará y ayudará en los problemas que puede encontrar a lo largo del camino el aprendizaje. Además, tendrán varios profesores que les enseñaran las distintas herramientas y buenas prácticas con las que trabajarán en su día a día.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/rocio-adalab.jpg&quot; alt=&quot;miembros de Codesai en WTMMadrid&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;internet-of-things-para-todos-qué-cosas-podemos-hacer-con-las-cosas&quot;&gt;INTERNET OF THINGS PARA TODOS ¿QUÉ COSAS PODEMOS HACER CON LAS COSAS?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/experiencia_T&quot;&gt;Marta Beltrán&lt;/a&gt; nos introdujo al fascinante mundo del “Internet de las Cosas” (IoT). En esta charla descubrimos el estado actual y todos los retos que aún quedan por delante para alcanzar un mundo en el que todos los dispositivos imaginables estén interconectados. Nos llamó mucho la atención lo avanzadas que están muchas industrias en este campo y la gran cantidad de estándares y tecnologías que ya existen y están siendo usadas. Los retos de seguridad que se plantean al tener todo inter-conectado parecen apasionantes.&lt;/p&gt;

&lt;h3 id=&quot;la-tecnología-también-es-cosa-de-niños&quot;&gt;¡LA TECNOLOGÍA TAMBIÉN ES COSA DE NIÑOS!&lt;/h3&gt;
&lt;p&gt;¡Una pequeña gran ponente! Alejandra, junto con la ayuda de sus padres, nos contó todo lo que había aprendido y sigue aprendiendo sobre la tecnología gracias a su fantástico robot JIMU. Un dinosaurio que ha tenido una aventura épica, la cual nos iba contando Alejandra mientras que JIMU se movía y bailaba.&lt;/p&gt;

&lt;p&gt;También asistimos a un &lt;strong&gt;taller&lt;/strong&gt;:&lt;/p&gt;

&lt;h3 id=&quot;taller-únete-a-la-rebelión-de-los-bots-y-la-inteligencia-artificial&quot;&gt;TALLER: ¡ÚNETE A LA REBELIÓN DE LOS BOTS Y LA INTELIGENCIA ARTIFICIAL!&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/0GiS0&quot;&gt;Gisela Torres&lt;/a&gt; nos hizo una introducción a los &lt;strong&gt;bots&lt;/strong&gt; y a la &lt;strong&gt;inteligencia artificial&lt;/strong&gt;, enseñándonos a crear nuestro primer bot que sea capaz de responder a las típicas FAQs de nuestra web. Para ello, nos enseñó su propio bot, muy chulo por cierto, donde simulaba un escenario donde la web era una compañía aérea y se nos perdía el equipaje. El bot nos ayudaba a que nos dejase nuestro equipaje en la ubicación que nosotros le indiquemos, haciendo uso de una verificación de dos pasos con un sms, y al resolver la incidencia era capaz de detectar nuestro estado de ánimo, y como simulamos que estábamos enfadados, el bot nos invitaba a entrar en la zona VIP la próxima vez que fueramos al aeropuerto debido a las molestias causadas.&lt;/p&gt;

&lt;p&gt;Estuvo muy divertido el taller y aprendimos bastantes cosas que podemos hacer para explotar todo el potencial de los &lt;a href=&quot;https://dev.botframework.com/&quot;&gt;bots&lt;/a&gt; y de los &lt;a href=&quot;https://www.microsoft.com/cognitive-services/en-us/qnamaker&quot;&gt;cognitive services&lt;/a&gt; de Microsoft.&lt;/p&gt;

&lt;p&gt;Slides del taller:&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/hpjtNtvmvqAx9W&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.returngis.net/2017/01/ensena-a-tu-bot-las-faqs-de-tu-empresa-con-qna-maker/&quot;&gt;Post - Enseña a tu bot las FAQs de tu empresa con QnA Maker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Muchísimas gracias y felicidades a l@s organizador@s del WTMMadrid. ¡El evento fue espectacular!.&lt;/p&gt;
</description>
          <pubDate>2017-04-10T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/estuvimos-en-women_tech_makers_madrid_2017</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/estuvimos-en-women_tech_makers_madrid_2017</guid>
        </item>
      
    
      
        <item>
          <title>Types of actions in a Redux App</title>
          <description>&lt;p&gt;In the &lt;a href=&quot;/2017/04/testing-strategies&quot;&gt;previous post&lt;/a&gt; there was a bunch of 
tests but not the code that make them pass. In the way we’re building 
apps with Redux, there are different kinds of actions and creators 
injected in the components. We usually talk just about actions without
distinction. These are the various kinds:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Redux action - a plain object: {type: ‘SOME_NAME’, data: someData}&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Redux action creator - a function returning an action:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  function actionCreator(){
      return {
          type: &apos;SOME_NAME&apos;,
          data: {some: &apos;data&apos;}
      };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Potential asynchronous action creators - supported by redux-thunk:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  function middlewarePoweredActionCreator(){
      return function(dispatch){
           return dispatch({
                  type: &apos;SOME_NAME&apos;,
                  data: {some: &apos;data&apos;
           });
      };
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Non-redux related actions:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  function nonReduxAction(fetch, data){
      return fetch(url, {
                  method: &apos;POST&apos;,
                  body: JSON.stringify(data)
              })
              .then((response) =&amp;gt; {
                  return Promise.resolve(response.json());
              });
      });
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are situations where the store’s state is not going to change, so 
there is no need for a reducer. If I
just want to send some data to the server, I don’t need the Redux 
machinery. I just post data from the component to the server through
my non-redux-related action. In the previous post about the 
&lt;a href=&quot;/2017/04/dependency-injection-react-redux&quot;&gt;factory&lt;/a&gt; I explained how
to map actions to the component. Action creators connected to Redux
must be &lt;em&gt;dispatched&lt;/em&gt; whereas non-redux actions must not.&lt;/p&gt;

&lt;p&gt;Asynchronous action creators are needed when data needs to be fetched 
from the server or sent to the server and passed through the 
reducers thus changing the store’s state.&lt;/p&gt;

&lt;p&gt;Populating store with data from server:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/76e8e4d8013a36cf465e5f71bf96dd82.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Processing data and changing the state before sending it to the server:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/6e67ae586a05dbd5d11690f49bbea8b7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Redux-thunk middleware provides two arguments to the function, &lt;em&gt;dispatch&lt;/em&gt;
and &lt;em&gt;getState&lt;/em&gt;. The first one triggers the reducers process and the second
gets the current state from the store.&lt;/p&gt;

&lt;p&gt;Action creators are just functions, they can be easily tested in isolation although
we usually test them in integration as described in previous posts.&lt;/p&gt;
</description>
          <pubDate>2017-04-05T19:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/types-of-actions</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/types-of-actions</guid>
        </item>
      
    
      
        <item>
          <title>Testing strategies in Redux</title>
          <description>&lt;p&gt;In the &lt;a href=&quot;/2017/04/test-driving-react-redux&quot;&gt;previous post&lt;/a&gt; I explained how to test-drive 
a Redux app from the outside-in with an example of a coarse-grained test integrating
most of the frontend layers. That was just one case but there are more cases, more kind of tests. 
These are the common things I like to check in my tests:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GUI events or &lt;em&gt;componentDidMount&lt;/em&gt; ends up with…
    &lt;ul&gt;
      &lt;li&gt;consistent changes in the store’s state.&lt;/li&gt;
      &lt;li&gt;consistent changes in the component’s state.&lt;/li&gt;
      &lt;li&gt;an async call to server, which response is properly handled.&lt;/li&gt;
      &lt;li&gt;no action calls at all, just display validation errors instead.&lt;/li&gt;
      &lt;li&gt;router redirections.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Store’s state is correctly rendered in the GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the items in the list are testable in integration using
Enzyme’s &lt;em&gt;mount&lt;/em&gt; function. Others however are better tested via 
Enzyme’s &lt;em&gt;shallow&lt;/em&gt;, in fact I’ve experienced situations where testing
with &lt;em&gt;mount&lt;/em&gt; is not possible because the component’s state is not 
accessible for instance or because the behavior is unpredictable.&lt;/p&gt;

&lt;p&gt;Let’s see an example. In our app, the component has a &lt;em&gt;notifier&lt;/em&gt; object
injected intended to show user messages such as the beginning of a 
potentially slow operation or the end of it. As some actions 
are is asynchronous, the test has to wait for all the things we want
to happen. Waiting is possible thanks to the &lt;em&gt;done&lt;/em&gt; argument provided by
the test framework - jest, mocha, jasmine…&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/4e7e19a3873f5d552c10969e89985859.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;When the expectation is not met, the test fails with a &lt;em&gt;timeout&lt;/em&gt; 
because &lt;em&gt;done&lt;/em&gt; is never called. However the failed expectation is 
also shown in the console. It’s a bit tricky because one have to 
scroll a bit to reach the actual failure reason in the output.&lt;/p&gt;

&lt;p&gt;We could further refactor the test above to make it less verbose and 
easier to change:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/14a0068b9fe81c655992f6267c8b0a45.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The next scenario is similar just a bit more complex. 
When the component loads,
it must fetch data from server to populate the store with it. This is
done inside &lt;em&gt;componentDidMount&lt;/em&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/88abb521cc594aeea29580a0155d6139.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The action is async, data is fetched from server and then dispatched 
via Redux. Thanks to 
redux-thunk middleware, the promise is resolved once the store has 
been updated. This is why we can expect the GUI to be refreshed.
In the next blog post I’ll write about the various kinds of actions.
The test can be refactored like before. I leave that for you.&lt;/p&gt;

&lt;p&gt;We could have written a finer test in terms of scope. We could have been
checked that server data has populated the store correctly:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/a65ac937958b113414f984a478500ba6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We’ve got access to the store instance so we can subscribe to it and
make assertions with the final state. Which test is best? it depends on
several aspects. I prefer to test-drive with coarse-grained tests but
if I feel the need to debug despite of writing small tests, I go for a
finer test like this. It’s a trade-off, confidence, brittleness 
and ease to understand and fix.&lt;/p&gt;

&lt;p&gt;There are occasions where checking the store is the only choice. One
 example is the &lt;em&gt;logout&lt;/em&gt; page:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/fac838dbdcd2d7afe509828d77d6d404.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;On line 8 I expect the store to be properly populated, before exercising
the code under test. As the logout action could be asynchronous, I 
wait for the store to change via &lt;em&gt;subscribe&lt;/em&gt; and then make the assertion.&lt;/p&gt;

&lt;p&gt;Up until now all the tests are &lt;em&gt;mounting&lt;/em&gt; the component and running
asynchronous tests. This technique is good enough when components are simple. 
Once they get more complex, for instance when they manage itw own
state calling &lt;em&gt;this.setState&lt;/em&gt;, small isolated tests are required. 
In these tests I usually stub or spy on actions thus testing the 
component in isolation. The next example tests a form that dynamically
renders input text boxes for every email in a list of emails:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/abed63b095e580bfa6afc91461815222.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;If one of the emails is going to be removed from the list using the form, I want to make sure the action receives the correct list:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/349b3004668a7f724f1cf46b8d508dff.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Synchronous tests are easier to reason about.&lt;/p&gt;

&lt;p&gt;I’ve experienced unpredictable behavior mixing both, synchronous and
asynchronous tests in the same suite when the system under test contains
components that manage their own state. It’s important to remember that
React’s &lt;em&gt;setState&lt;/em&gt; is asynchronous although the name of the function 
doesn’t look like it is. I haven’t got the time to analyze
the problem and see whether it’s in React Test Utilities, in Enzyme,…
but I just try to keep those tests in separate test suites.&lt;/p&gt;
</description>
          <pubDate>2017-04-05T18:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/testing-strategies</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/testing-strategies</guid>
        </item>
      
    
      
        <item>
          <title>Test-driving a Redux App</title>
          <description>&lt;p&gt;I like starting every new feature with a failing coarse-grained test that exercises most
of the layers I’ll have to cross in order to get the feature done. During that cycle
I may write smaller tests to get faster feedback. Pretty much anytime I feel the need
to debug my big test, I rather write small tests to confirm that smaller chunks of 
code work as expected. Some of those tests will stay when
development is done and some others will be deleted, they are used only as a scaffolding
mechanism. This is one way to approach outside-in TDD. 
In a frontend app, the boundaries of the system are the server API and the
GUI. I usually stub or spy on the server API - a simple AJAX client. However I do use
the actual GUI, well, in the case of React the wrapper provided by
 &lt;a href=&quot;https://github.com/airbnb/enzyme&quot;&gt;Enzyme&lt;/a&gt;’s &lt;em&gt;mount&lt;/em&gt;, because it’s fast anyway and 
gives me a feeling of realistic behavior. The server API is pretty much the only thing
I mock, for everything else I prefer to use the actual artifacts.&lt;/p&gt;

&lt;p&gt;For the Profile Page described in the 
previous post, this would be a good test to start from:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/6e9246e00b2a8eaaafb89b1a0bb123e8.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Initially the store contains an empty profile to render the page. At the beginning of 
the test I wait for the profile to be retrieved from the server. I assume 
the download is finished as soon as the notifier is called to let the user know about
 the end of the request. At that
point the action should have been dispatched by Redux and I can assert that the form 
renders the server’s data. Here I am stubbing out the query to the server and spying
on the notifier method which is a void function.&lt;/p&gt;

&lt;p&gt;In order to make this test pass I must write the action, the reducer and the method in
the component. Notice that I am using the factory we saw in the &lt;a href=&quot;/2017/04/dependency-injection-react-redux&quot;&gt;previous post&lt;/a&gt;. This 
would be the code required by the component:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/1cdb307a7ba53e4689329ed3241edc10.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The test above covers the factory which includes the call to &lt;em&gt;connect&lt;/em&gt; thus testing
 &lt;em&gt;mapStateToProps&lt;/em&gt; and &lt;em&gt;mapDispatchToProps&lt;/em&gt;. It also covers the stores’ 
 configuration and the component including all its children. It integrates pretty much
 all the layers. Only routing and server side are left out. It’s fast to run and gives 
 me a lot of confidence. I can write additional fine-grained tests for the reducer in
 isolation or the component using Enzyme’s &lt;em&gt;shallow&lt;/em&gt;. In fact, as we’ll explore in an
 upcoming blog post, Enzyme’s &lt;em&gt;mount&lt;/em&gt; is not the best fit for components that handle
 their own state calling React’s &lt;em&gt;setState&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In case you miss it, this is the rest of the code required by the test:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/1f78f0ef6e198c637a91e9ace3ebb2d2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The action creator above requires react-thunk middleware to work.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/3e54676e002623b4d8fb80b083e6d1f5.js&quot;&gt;&lt;/script&gt;

</description>
          <pubDate>2017-04-05T16:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/test-driving-react-redux</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/test-driving-react-redux</guid>
        </item>
      
    
      
        <item>
          <title>Dependency Injection in Redux</title>
          <description>&lt;p&gt;Redux provides a function called &lt;em&gt;connect&lt;/em&gt; that binds the component to the store. This
is the place where state and actions are map to component properties and also where 
the component subscribes to changes in the store. Well, the subscription happens as 
long as React’s &lt;strong&gt;Provider&lt;/strong&gt; is in place:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/ba0a2d955a018dc91e3fa507fd49383e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We invoke &lt;em&gt;connect&lt;/em&gt; from our component &lt;strong&gt;factory&lt;/strong&gt;. An example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/613f5a1e0d997eac8855a852c467cf86.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The production code would import &lt;em&gt;ProfilePage&lt;/em&gt; - last line. Tests will 
import and use &lt;em&gt;createProfilePage&lt;/em&gt; in order to inject test doubles to mock the 
API and other dependencies like the &lt;em&gt;notifier&lt;/em&gt; - a simple wrapper around an alert dialog.
The first &lt;em&gt;connect&lt;/em&gt; argument is the function that maps the global state to the 
component’s state. The second argument makes actions available to the component. We
distinguish two kind of actions. Those that impact on the state and those
which don’t. If the action is going to be processed by a reducer that in turn is going to 
change the state, then a call to &lt;em&gt;dispatch&lt;/em&gt; is needed - lines 18 &amp;amp; 24. In fact
 those functions are action creators, they return an object or another function
 to be dispatched asynchronously with the help of &lt;a href=&quot;https://github.com/gaearon/redux-thunk&quot;&gt;thunk middleware&lt;/a&gt;. 
 Function &lt;em&gt;dispatch&lt;/em&gt; is provided by Redux, like &lt;em&gt;connect&lt;/em&gt;. On the other hand
if the action does not alter the state of the frontend app, we just invoke it and return
it’s result, which is typically a promise - line 21. We are not using the helper function
 &lt;em&gt;bindActionCreators&lt;/em&gt; from Redux to make it explicit where we need its machinery and
 where we don’t&lt;/p&gt;

&lt;p&gt;In both cases, closures hide the fact that actions require the serverApi to work, 
making its usage simpler for the component - the consumer. 
ProfilePage component will invoke the action like this:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/0c28de1038ba9032506ec74ddafc299b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;I am far from being a Redux expert and I guess some people will find it unusual to not
call &lt;em&gt;dispatch&lt;/em&gt; every time. Notice that &lt;em&gt;saveProfile&lt;/em&gt; is not an action creator but just
 a function that return a promise. However I find this code simpler, I don’t see the
 point in going through a reducer when the state is not going to be changed.&lt;/p&gt;

&lt;p&gt;Actions and action creators:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/carlosble/cc4bf2a2c6a301971e5a7f5531248ef2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Given this factory, in the &lt;a href=&quot;/2017/04/test-driving-react-redux&quot;&gt;next blog post&lt;/a&gt; I’ll explain how we test-drive the app from
 the outside-in, as well as the various kind of tests.&lt;/p&gt;
</description>
          <pubDate>2017-04-05T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/dependency-injection-react-redux</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/dependency-injection-react-redux</guid>
        </item>
      
    
      
        <item>
          <title>Getting started with React &amp; Redux</title>
          <description>&lt;p&gt;I started learning React and Redux about two months ago. Following the recommendation of 
my colleagues Dani, Miguel &amp;amp; Ronny, I went to Pluralsight to study from the great training 
courses carefully crafted by &lt;a href=&quot;https://twitter.com/housecor&quot;&gt;Cory House&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We first watched the introduction to &lt;a href=&quot;https://app.pluralsight.com/library/courses/react-flux-building-applications/table-of-contents&quot;&gt;React and Flux&lt;/a&gt;. 
I did not practice with the exercises proposed, just watched the episodes at the 
maximum speed I could. It’s nice to be able to configure the player’s speed to 1.7x or 2x.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/react-redux.jpg&quot; alt=&quot;Redux&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once I understood React and the Flux pattern I went to the next course on &lt;a href=&quot;https://app.pluralsight.com/library/courses/react-redux-react-router-es6/table-of-contents&quot;&gt;React and Redux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time I downloaded the repository that Cory’s got for this course, called 
&lt;a href=&quot;https://github.com/coryhouse/pluralsight-redux-starter&quot;&gt;Pluralsight-redux-starter&lt;/a&gt; 
and played with the examples along the way. I appreciated specially the episodes in 
testing since I am a test infected developer and I feel the need for tests as soon as
I get started with the development.&lt;/p&gt;

&lt;p&gt;Cory has a terrific code repository called &lt;a href=&quot;https://github.com/coryhouse/react-slingshot&quot;&gt;React-Slingshot&lt;/a&gt; that served us to boot our first Redux project. It’s similar to the Pluralsight Starter but production ready, with an incredibly 
powerful Webpack setup including all the tests harness, hot reloading, Babel…
The repository includes cutting-edge libraries and works perfectly on Linux, Windows
and Mac. Ready to work with ES6 which is the JavaScript flavour we’ve been using in
the last two years. It saved us a lot of time, I am very grateful Cory!&lt;/p&gt;

&lt;p&gt;In the course there is an example where Cory tests a component through the Redux Provider. This one example has been very useful for us because we like to do Outside-in TDD and testing from the Provider allows us to write integration tests that
cover the factory and &lt;em&gt;Redux’s connect&lt;/em&gt; with our implementations of &lt;em&gt;mapStateToProps&lt;/em&gt; and &lt;em&gt;mapStateToActions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the following blog post I’ll explain our Outside-in TDD strategy together with the
dependency injection which are building blocks that are not covered by the courses.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;p&gt;By the way, at the time of this writing there is an offer by Microsoft. Registering 
at &lt;a href=&quot;https://www.visualstudio.com/dev-essentials/&quot;&gt;Visual Studio Dev Essentials&lt;/a&gt; gives
you free access to Pluralsight for three months.&lt;/p&gt;

</description>
          <pubDate>2017-04-03T08:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/04/getting-started-react-redux</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/04/getting-started-react-redux</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Biosystems</title>
          <description>&lt;p&gt;Hace algunas semanas estuve impartiendo el &lt;a href=&quot;http://www.codesai.com/curso-de-tdd/&quot;&gt;curso de TDD de Codesai&lt;/a&gt; en las oficinas de &lt;a href=&quot;http://www.biosystems.es/&quot;&gt;Biosystems&lt;/a&gt; en Barcelona.&lt;/p&gt;

&lt;p&gt;Se trata de una empresa que lleva más de 30 años investigando, desarrollando y fabricando sistemas analíticos de diagnóstico clínico y agroalimentario para laboratorios de todo el mundo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/biosystems1.png&quot; alt=&quot;una de sus máquinas de diagnóstico&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Les visité en época de cambios, con nuevos proyectos arrancando, en un momento muy interesante porque las mentes estaban abiertas y había muchas ganas de aprender y compartir.&lt;/p&gt;

&lt;p&gt;Posiblemente el motivo de que nos llamasen fue que algunas personas del equipo como &lt;a href=&quot;https://twitter.com/nhan_bcn&quot;&gt;Ana Carmona&lt;/a&gt; me conocían de eventos como la &lt;a href=&quot;http://www.cas2015.agile-spain.org/charlas-y-videos/&quot;&gt;CAS2015&lt;/a&gt; o la &lt;a href=&quot;https://cas2016.agile-spain.org/&quot;&gt;CAS2016&lt;/a&gt; y propusieron a la empresa que nos contratasen. A menudo entramos en las empresas así, por sugerencia de algún miembro del equipo que habla de nosotros a las personas que tienen poder de contratación dentro de su organización.&lt;/p&gt;

&lt;p&gt;Lo mejor de todo fue el trato tan cercano y cálido que me brindaron desde el primer momento. No solo durante el trabajo sino después poder irnos juntos a cenar e incluso recogerme en coche para ir hasta la oficina o acompañarme hasta el tren de regreso a casa. Sin duda el equipo humano de Biosystems es excepcional, son el mayor tesoro de la organización.&lt;/p&gt;

&lt;p&gt;Desarrollan en el mismo edificio absolutamente todas las piezas de sus productos, tanto el hardware como el firmware como el software. Nada de externalizar la fabricación a otros países, es todo &lt;em&gt;made in Barcelona&lt;/em&gt;. Además de la formación estuve como consultor estudiando con el equipo cómo se podrían automatizar los tests de todas las partes, incluyendo los &lt;em&gt;end-to-end&lt;/em&gt; que validasen que el software se comunica bien en el firmware y que éste a su vez coordina bien toda la electromecánica de las máquinas. Máquinas muy complejas con varios brazos robóticos que toman muestras, las mezclan y las analizan. Me quedé alucinado cuando ví una de las más grandes desmontada y funcionando, o sea cuando le vi las tripas, sin la carcasa. Estas máquinas operan en tiempo real, cualquier mínimo retraso del firmware provocaría que los brazos colisionasen. Los tests &lt;em&gt;end-to-end&lt;/em&gt; manuales son muy costosos porque los procesos pueden durar hasta 15 minutos ya que las máquinas tienen programas de inicio que limpian los inyectores, etc. Por todo ello el reto es muy grande. Lógicamente se están haciendo tests de piezas separadas que hablan con &lt;em&gt;fakes&lt;/em&gt; y otros tipos de mocks. Los siguientes pasos son muy interesantes pero no los desvelaré por si se trata de información reservada.&lt;/p&gt;

&lt;p&gt;El equipo de ingenieros que desarrolla el firmware tuvo la amabilidad de dedicarme una tarde para mostrarme el código fuente, hecho en lenguaje C, las herramientas de desarrollo, el hardware y la problemática a que se enfrentan. Aproveché para hacer preguntas sobre cómo plataformas como Raspberry o Arduino afectan a la industria, a lo que ellos, aparte de ver que no tengo ni idea de hardware ni firmware, me respondieron que en la industria ellos tienen que comprar piezas industriales (chips, buses, etc) a empresas que les garantizan que al menos por 10 años van a encontrar repuestos. Sus máquinas se diseñan y fabrican para que duren toda la vida. Tienen laboratorios donde hacen pruebas de duración de las diferentes piezas mecánicas, las ponen a funcionar hasta que se rompen para garantizar su calidad.&lt;/p&gt;

&lt;p&gt;Usan buses de comunicación de la automoción por su probada estabilidad y resistencia. La gran variedad de chips a elegir y su complejidad (los manuales con los juegos de instrucciones y las patas dan miedo) hace que se necesite muchísima investigación y pruebas para armar las máquinas más robustas posibles. Me contaron que la &lt;a href=&quot;https://es.wikipedia.org/wiki/Arquitectura_ARM&quot;&gt;arquitectura ARM&lt;/a&gt; sí está siendo el revulsivo en el sector, al abaratar y simplificar el diseño de chips, permitiendo que salgan cada vez placas más potentes que ocupan poco espacio. Parece que la tendencia es hacia poder usar C++ en más áreas del firmware y disponer de librerías de más alto nivel que reducirían mucho la complejidad actual, incluso con posibilidad de correr Linux. Unido al &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_of_things&quot;&gt;IoT&lt;/a&gt; (Internet de las cosas), el futuro se prevé muy interesante.&lt;/p&gt;

&lt;p&gt;La parte software lo que hace es programar los diagnósticos, casando las muestras de los pacientes con los líquidos reactivos que corresponde usar para diagnosticar enfermedades. Software y firmware se comunican mediante eventos.&lt;/p&gt;

&lt;p&gt;La colaboración entre los distintos equipos de ingeniería es estupenda, estoy seguro de que se van a seguir superando a sí mismos constantemente. Así que estoy muy contento de haber pasado por allí para compartir y aprender.&lt;/p&gt;

&lt;p&gt;Ha sido un placer!&lt;/p&gt;
</description>
          <pubDate>2017-03-26T10:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/03/estuvimos-en-biosystems</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/03/estuvimos-en-biosystems</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en DeveloperOS Madrid 2017</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/codesai_en_developeros.png&quot; alt=&quot;miembros de Codesai en DeveloperOs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para comenzar 2017 con buen pie varios miembros de Codesai estuvimos en el &lt;a href=&quot;http://developeros.net/&quot;&gt;DeveloperOS&lt;/a&gt;, un &lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Space_Technology&quot;&gt;Open Space&lt;/a&gt; centrado en tecnologías .Net que organizó la &lt;a href=&quot;https://www.meetup.com/madriddotnet/&quot;&gt;comunidad .Net de Madrid&lt;/a&gt; el pasado 28 de Enero y del que fuimos uno de los patrocinadores. Aunque era la primera edición de este evento las entradas se acabaron enseguida. Últimamente hay que correr para poder pillar entrada casi para cualquier evento :)&lt;/p&gt;

&lt;p&gt;El evento duró desde las 9 de la mañana hasta las 19:30. A lo que hay que sumarle algunas horas más para aquéllos que nos fuimos a tomar unas cervezas y charlar después de la retro y el sorteo de regalitos de los partners.&lt;/p&gt;

&lt;p&gt;La organización del evento fue estupenda, como se vio reflejado en la retrospectiva final donde se puede decir que no había nada negativo. No hubo ningún problema de retrasos en las charlas gracias a unos intervalos de 15 minutos entre ellas y al gran trabajo de los organizadores.&lt;/p&gt;

&lt;p&gt;Por otro lado fue un puntazo que trajeran el desayuno y la comida para poder comer y  hacer networking sin tener que moverse del lugar del evento, por no mencionar que estaba fleje buena ;). Además, siempre estaban disponibles la máquina de café y algunos refrigerios o fruta para todo aquél que se quedase fuera de una charla mientras conversaba con otros asistentes.&lt;/p&gt;

&lt;p&gt;También queríamos agradecer a la &lt;a href=&quot;http://www.urjc.es/inicio&quot;&gt;Universidad Rey Juan Carlos&lt;/a&gt; por ceder sus instalaciones para la celebración del evento.&lt;/p&gt;

&lt;p&gt;En lo que se refiere a los asistentes hay que destacar la gran participación que hubo en las charlas y el nivelazo en general, las conversaciones de pasillo dieron pie a debates y reflexiones muy interesantes.&lt;/p&gt;

&lt;p&gt;Asistimos a las siguientes charlas:&lt;/p&gt;

&lt;h3 id=&quot;versionado-de-apis-rest-con-aspnet-core&quot;&gt;Versionado de APIs REST con ASP.NET Core.&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/rliberoff&quot;&gt;Rodrigo Liberoff&lt;/a&gt; nos contó que siempre hay que versionar las APIs REST que hagamos, ya que si no versionamos es porque no queremos. También nos enseñó un paquete de NuGet &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Versioning&quot;&gt;Microsoft ASP.NET Core API Versioning&lt;/a&gt; que ayuda a versionar y con el que nos hizo una demo de las variantes de versionar nuestra API.&lt;/p&gt;

&lt;h3 id=&quot;tests-de-integración-de-web-apis&quot;&gt;Tests de integración de Web APIs&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/hbiarge&quot;&gt;Hugo Biarge&lt;/a&gt; nos enseñó una manera sencilla de hacer tests de integración de nuestra Web API. Y además nos hizo una demo con el paquete de NuGet &lt;a href=&quot;https://github.com/hbiarge/Acheve.Owin.Testing.Security&quot;&gt;Acheve.Owin.Testing.Security&lt;/a&gt; de problemas comunes que te puedes encontrar al hacer este tipo de tests,  como, por ejemplo, si un usuario está logueado y entra al sistema, o que esté logueado pero no tiene permisos para entrar en ciertas rutas, etc. Fue una charla muy entretenida.&lt;/p&gt;

&lt;p&gt;Estuvimos bastante tiempo metidos en conversaciones de pasillo y conociendo gente nueva, por lo que nos perdimos muchas charlas. Además, dimos varios charlas:&lt;/p&gt;

&lt;h3 id=&quot;comunicación-no-violenta&quot;&gt;Comunicación No Violenta&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/SuuiGD&quot;&gt;Dani&lt;/a&gt; propuso una charla sobre &lt;a href=&quot;https://en.wikipedia.org/wiki/Nonviolent_Communication&quot;&gt;Comunicación No Violenta&lt;/a&gt; después de leerse un poco menos de la mitad del libro de &lt;a href=&quot;https://en.wikipedia.org/wiki/Marshall_Rosenberg&quot;&gt;Marshall Rosenberg&lt;/a&gt; en el avión a Madrid. Como le tocó a primera hora, tuvo que improvisar, pero tras una breve introducción el nivel de participación de los asistentes ya era alto. Expuso un poco las bases de los capítulos que había leído y los ejercicios del libro provocaron mucho debate.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/dosconf_dani_3.png&quot; alt=&quot;miembros de Codesai en DeveloperOs&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;testing-behavior-instead-of-components&quot;&gt;Testing behavior instead of components&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/RonnyAncorini&quot;&gt;Ronny&lt;/a&gt; propuso un debate sobre testear comportamiento vs testear componentes. Con esto se refería a tratar de aislarse de las implementaciones de diseño y subir el nivel de abstracción de los tests para reducir el acoplamiento. Ronny acompañó el debate mostrando tests reales que han desarrollado en &lt;a href=&quot;https://www.aidacanarias.com/&quot;&gt;AIDA&lt;/a&gt;. &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel&lt;/a&gt; en los últimos minutos también se animó a mostrar algún test. Los asistentes estuvieron muy activos y los ejemplos ofrecían casos límite muy interesantes. Creo que todos tuvimos la oportunidad de aprender y además nosotros salimos muy contentos con el feedback recibido enseñando código. Sin duda, animamos a la comunidad a mostrar su código, obtener feedback de gente tan buena no tiene precio.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/dosconf_ronny_3.png&quot; alt=&quot;miembros de Codesai en DeveloperOs&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;refactoring&quot;&gt;Refactoring&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/RonnyAncorini&quot;&gt;Ronny&lt;/a&gt; montaron una mesa redonda sobre refactoring, hablando sobre estrategias que aplican en sus entornos de trabajo y las herramientas que usan en su día a día para mejorar su flujo. El debate estuvo servido porque los asistentes participaron mucho contando desde su perspectiva el cómo lidiar con personas de negocio y  en situaciones no merece la pena afrontar un refactor durante el desarrollo. Sin duda fue una sesión de donde rescatar muchas frases interesantes y de gran valor.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/dosconf_ronny_miguel_1.jpg&quot; alt=&quot;miembros de Codesai en DeveloperOs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Muchísimas gracias y felicidades a los organizadores de DeveloperOS. ¡El evento fue espectacular!&lt;/p&gt;
</description>
          <pubDate>2017-02-14T08:08:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/02/estuvimos-en-developeros</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/02/estuvimos-en-developeros</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre sequence comprehensions en Clojure</title>
          <description>&lt;p&gt;Ayer grabamos nuestro tercera charla remota sobre Clojure como parte de las actividades que hacemos en nuestro pequeño grupo de estudio de Clojure/ClojureScript.&lt;/p&gt;

&lt;p&gt;El tema de esta charla fue las sequence comprehensions usando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Aquí les comparto la grabación de la charla:&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;rxegilFlZIc&quot;&gt;
    &lt;div data-id=&quot;rxegilFlZIc&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/rxegilFlZIc/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;y aquí pueden encontrar &lt;a href=&quot;https://gist.github.com/trikitrok/b10e2af0225f85491728&quot;&gt;los ejemplos que usamos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez más, me gustaría darle las gracias a &lt;a href=&quot;https://twitter.com/rojo_angel&quot;&gt;Ángel&lt;/a&gt; por su ayuda y paciencia.&lt;/p&gt;

&lt;p&gt;Espero que les resulte útil.&lt;/p&gt;
</description>
          <pubDate>2017-02-10T00:08:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/02/charla-clojure-sequence-comprehensions</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/02/charla-clojure-sequence-comprehensions</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Test Academy</title>
          <description>&lt;p&gt;El pasado 25 de Enero tuve la suerte de formar parte de  Test Academy en Barcelona, dirigiendo y facilitando una conversación sobre Behavior-driven development (BDD).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/test_academy_carlos.jpg&quot; alt=&quot;Carlos dando su taller de BDD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El objetivo de Test Academy es reunir a profesionales y expertos de la comunidad de testing y desarrollo de software durante un día para aprender, intercambiar experiencias y hacer networking. Este año hubo 8 sesiones que cubrieron una gran variedad de temas. La organización del evento me pareció brillante, el hotel era estupendo y todo funcionaba perfectamente. La zona de cafés y comida era estupenda para el networking y pude desvirtualizar a mucha gente que todavía no había tenido oportunidad de saludar en persona.&lt;/p&gt;

&lt;p&gt;En cuanto a las sesiones, que no fuese la mía, sólo pude asistir a la de &lt;a href=&quot;https://twitter.com/mrsdaehin&quot;&gt;Almudena Vivanco&lt;/a&gt; sobre Web Performance. El resto de sesiones me las perdí muy a mi pesar, no pude asistir. Me encantó la sesión de Almudena, me apunté un buen set de herramientas imprescindibles como por ejemplo &lt;a href=&quot;https://www.webpagetest.org/&quot;&gt;Web Page Test&lt;/a&gt;, que da una cantidad de información extremadamente útil. Mil cosas que herramientas como &lt;a href=&quot;http://jmeter.apache.org/&quot;&gt;JMeter&lt;/a&gt; no permiten medir. Fué una sesión entretenida y muy valiosa.&lt;/p&gt;

&lt;p&gt;Mi sesión estaba anunciada como una master class, básicamente porque no me dí cuenta hasta que faltaba poquito para el evento y ya no la pude cambiar. En realidad tratándose de una hora y media, prefería que hubiese participación de los asistentes. Cuando la gente hace preguntas y comparte experiencias puedo centrarme en compartir el conocimiento que creo que más valor les puede aportar. Además las opiniones de los asistentes me permiten aprender a mí también, escuchar las experiencias de los demás es muy enriquecedor. La aportación de &lt;a href=&quot;https://twitter.com/twiindan&quot;&gt;Antonio Robres&lt;/a&gt; durante mi sesión fue un aporte muy interesante. También permite hacerse una idea de cual es el nivel de adaptación de BDD en diferentes equipos y empresas. La hora y media se me pasó volando y el nivel de participación fue bastante alto pero a haber pillado por sorpresa a los participantes y a que la sala no tenía una distribución cómoda para hacer debate.&lt;/p&gt;

&lt;p&gt;Después de la sesión tuve la suerte de poder tomar café con algunas personas que habían estado en la sesión y que comentaban que se llevaban varias idea para poner en práctica, lo cual es una satisfacción.&lt;/p&gt;

&lt;p&gt;Estas son las slides que utilicé:&lt;/p&gt;
&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/ukaCysdj7qdhG&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Muchísimas gracias a los organizadores de Test Academy por montar un evento tan guapo y por darme la oportunidad de ser parte de él. Especialmente a &lt;a href=&quot;https://twitter.com/grahampmoran&quot;&gt;Graham Moran&lt;/a&gt;, siempre tan amable y atento.&lt;/p&gt;
</description>
          <pubDate>2017-02-01T08:08:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/02/estuvimos-en-test-academy</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/02/estuvimos-en-test-academy</guid>
        </item>
      
    
      
        <item>
          <title>Impartimos un curso abierto de TDD en Barcelona</title>
          <description>&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;La semana pasada &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;Carlos&lt;/a&gt; y yo impartimos un &lt;a href=&quot;http://www.codesai.com/curso-de-tdd/&quot;&gt;curso de TDD&lt;/a&gt; en Barcelona en formato abierto.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/barcelona_2017_01_foto_grupo.jpg&quot; alt=&quot;asistentes al curso abierto de TDD en Barcelona&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Los cursos en abierto son siempre muy gratificantes porque los asistentes vienen con muchísimas ganas de trabajar y de aprender. De hecho, varios de ellos pagaron el curso de su propio bolsillo e incluso vinieron de otras comunidades. Muchísimas gracias a todos por venir y por su entusiasmo. Los cursos en abiertos son también muy interesantes porque en ellos solemos conocer a gente muy apasionada por su trabajo, que, en ocasiones, acaba colaborando con Codesai, como fue mi caso o el de &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Este fue el primer curso que imparto con Carlos. La versión de curso que hace Carlos tiene una estructura más pausada que la de Luis. Se hacen varios ejercicios de testing y de refactoring antes de empezar a hacer TDD, que luego vienen muy bien. Aprendí muchas cosas de Carlos, tanto de sus comentarios como de la forma de tratar a las personas. En algunas cosas pensamos diferente, pero eso añade riqueza al curso.&lt;/p&gt;

&lt;p&gt;Hacer los cursos en pareja es una gran ventaja cuando el grupo es grande porque el nivel de atención que recibe cada participante es mucho más alto. Esto es importante, porque nuestra formación es muy práctica, y estamos constantemente contestando a dudas y dando feedback a nuestros alumnos para que asimilen mejor los conceptos que queremos trabajar con cada kata. Además, el hecho de tener backgrounds distintos y personalidades diferentes, enriquece tanto las explicaciones teóricas como las prácticas, ya que podemos aportar un rango de experiencias, técnicas y perspectivas mucho más amplio.&lt;/p&gt;

&lt;p&gt;Acabamos muy contentos con las sensaciones que tuvimos durante el curso y con el feedback que recibimos.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;es&quot;&gt;
        &lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Fantastic &lt;a href=&quot;https://twitter.com/codesaidev&quot;&gt;@codesaidev&lt;/a&gt; 2-day &lt;a href=&quot;https://twitter.com/hashtag/tdd?src=hash&quot;&gt;#tdd&lt;/a&gt; training with &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;@trikitrok&lt;/a&gt;. 👏 Lots of insights 🎯 and food for thought 💡 &lt;a href=&quot;https://t.co/TbjEUooHDH&quot;&gt;pic.twitter.com/TbjEUooHDH&lt;/a&gt;&lt;/p&gt;&amp;mdash; Angel (@rojo_angel) &lt;a href=&quot;https://twitter.com/rojo_angel/status/823973994466594817&quot;&gt;24 de enero de 2017&lt;/a&gt;
      &lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;es&quot;&gt;
        &lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Genial two-day training sobre TDD impartido por  &lt;a href=&quot;https://twitter.com/codesaidev&quot;&gt;@codesaidev&lt;/a&gt; in house aquí en &lt;a href=&quot;https://twitter.com/magento&quot;&gt;@magento&lt;/a&gt; BCN. &lt;a href=&quot;https://t.co/rKr4ORiSl6&quot;&gt;pic.twitter.com/rKr4ORiSl6&lt;/a&gt;&lt;/p&gt;&amp;mdash; Rubén Cougil (@rcougil) &lt;a href=&quot;https://twitter.com/rcougil/status/823941312630161408&quot;&gt;24 de enero de 2017&lt;/a&gt;
      &lt;/blockquote&gt;
  &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-5 col-md-offset-4 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Dos días de TDD training de la mano de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;@trikitrok&lt;/a&gt;. 100% recomendable 😀 &lt;a href=&quot;https://t.co/8Zj28qBEDs&quot;&gt;pic.twitter.com/8Zj28qBEDs&lt;/a&gt;&lt;/p&gt;&amp;mdash; Víctor Andevert (@victorandevert) &lt;a href=&quot;https://twitter.com/victorandevert/status/823984066819227648&quot;&gt;January 24, 2017&lt;/a&gt;
      &lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;Nos gustaría mucho darle las gracias a &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento&lt;/a&gt; y especialmente a &lt;a href=&quot;https://twitter.com/rojoangel&quot;&gt;Ángel Rojo&lt;/a&gt; por acogernos en sus oficinas y organizarlo todo tan bien. Tanto la sala como el espacio que reservaron para relajarse y tomar café como el catering estuvieron genial.&lt;/p&gt;

</description>
          <pubDate>2017-01-31T08:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/curso-abierto-tdd-en-bcn</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/curso-abierto-tdd-en-bcn</guid>
        </item>
      
    
      
        <item>
          <title>About Connascence</title>
          <description>&lt;p&gt;Lately at Codesai we’ve been studying and applying the concept of &lt;a href=&quot;http://connascence.io/&quot;&gt;connascence&lt;/a&gt; in our code and even have done &lt;a href=&quot;http://slides.com/franreyesperdomo/connascence#/&quot;&gt;an introductory talk about it&lt;/a&gt;. We’d like this post to be the first of a series of posts about connascence.&lt;/p&gt;

&lt;h3 id=&quot;1-origin&quot;&gt;1. Origin.&lt;/h3&gt;

&lt;p&gt;The concept of &lt;strong&gt;connascence&lt;/strong&gt; is not new at all. &lt;a href=&quot;https://www.linkedin.com/in/meilir-page-jones-a55132&quot;&gt;Meilir Page-Jones&lt;/a&gt; introduced it in 1992 in his paper &lt;a href=&quot;http://wiki.cfcl.com/pub/Projects/Connascence/Resources/p147-page-jones.pdf&quot;&gt;Comparing Techniques by Means of Encapsulation and Connascence&lt;/a&gt;. Later, he elaborated more on the idea of &lt;strong&gt;connascence&lt;/strong&gt; in his &lt;a href=&quot;https://www.amazon.com/Every-Programmer-Should-Object-Oriented-Design/dp/0932633315&quot;&gt;What every programmer should know about object-oriented design&lt;/a&gt; book from 1995, and its more modern version (same book but using UML) &lt;a href=&quot;https://www.amazon.com/Fundamentals-Object-Oriented-Design-Meilir-Page-Jones/dp/020169946X/ref=asap_bc?ie=UTF8&quot;&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt; from 1999.&lt;/p&gt;

&lt;p&gt;Ten years later, &lt;a href=&quot;https://en.wikipedia.org/wiki/Jim_Weirich&quot;&gt;Jim Weirich&lt;/a&gt;, brought &lt;strong&gt;connascence&lt;/strong&gt; back from oblivion in a series of talks: &lt;a href=&quot;https://www.youtube.com/watch?time_continue=2890&amp;amp;v=NLT7Qcn_PmI&quot;&gt;Grand Unified Theory of Software Design&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=l780SYuz9DI&quot;&gt;The Building Blocks of Modularity&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=HQXVKHoUQxY&quot;&gt;Connascence Examined&lt;/a&gt;. As we’ll see later in this post, he did not only bring &lt;strong&gt;connascence&lt;/strong&gt; back to live, but also improved its exposition.&lt;/p&gt;

&lt;p&gt;More recently, &lt;a href=&quot;https://silkandspinach.net/&quot;&gt;Kevin Rutherford&lt;/a&gt;, wrote a very interesting series of posts, in which he talked about using &lt;strong&gt;connascence&lt;/strong&gt; as a guide to choose the most effective refactorings and about how &lt;strong&gt;connascence&lt;/strong&gt; can be a more objective and useful tool than code smells to identify design problems&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;2-what-is-connascence&quot;&gt;2. What is connascence?&lt;/h3&gt;

&lt;p&gt;The concept of &lt;strong&gt;connascence&lt;/strong&gt; appeared in a time, early nineties, when OO was starting its path to become the dominant programming paradigm, as a general way to evaluate design decisions in an OO design. In the previous dominant paradigm,  &lt;a href=&quot;https://en.wikipedia.org/wiki/Structured_programming&quot;&gt;structured programming&lt;/a&gt;, &lt;strong&gt;fan-out&lt;/strong&gt;, &lt;strong&gt;coupling&lt;/strong&gt; and &lt;strong&gt;cohesion&lt;/strong&gt; were fundamental design criteria used to evaluate design decisions. To make clear what Page-Jones understood by these terms, let’s see the definitions he used:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Fan-out&lt;/strong&gt; is a measure of the number of references to other procedures by lines of code within a given procedure.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Coupling&lt;/strong&gt; is a measure of the number and strength of connections between procedures.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Cohesion&lt;/strong&gt; is a measure of the “single-mindedness” of the lines of code within a given procedure in meeting the purpose of that procedure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;According to Page-Jones, these design criteria govern the interactions between the &lt;a href=&quot;https://books.google.es/books?id=iNAezyMExBkC&amp;amp;pg=PA210&amp;amp;lpg=PA210&amp;amp;dq=levels+of+encapsulation&amp;amp;source=bl&amp;amp;ots=BLv-66F9xq&amp;amp;sig=vaJWjQYq1Bc3_0MHQSKza5y7BiU&amp;amp;hl=en&amp;amp;sa=X&amp;amp;ved=0ahUKEwjF_cy7l-rQAhUBXhQKHSsoCJoQ6AEILjAC#v=onepage&amp;amp;q=levels%20of%20encapsulation&amp;amp;f=false&quot;&gt;levels of encapsulation&lt;/a&gt; that are present in structured programming: level-1 encapsulation (the subroutine) and level-0 (lines of code), as can be seen in the following table from &lt;a href=&quot;https://www.amazon.com/Fundamentals-Object-Oriented-Design-Meilir-Page-Jones/dp/020169946X/ref=asap_bc?ie=UTF8&quot;&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/encapsulation_structured_programming.png&quot; alt=&quot;Encapsulation levels and design criteria in structured programming&quot; /&gt;
    &lt;figcaption&gt;&lt;strong&gt;Encapsulation levels and design criteria in structured programming&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;However, OO introduces at least level-2 encapsulation, (the class), which  encapsulates level-1 constructs (methods) together with attributes. This introduces many new interdependencies among encapsulation levels, which will require new design criteria to be defined, (see the following table from &lt;a href=&quot;https://www.amazon.com/Fundamentals-Object-Oriented-Design-Meilir-Page-Jones/dp/020169946X/ref=asap_bc?ie=UTF8&quot;&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt;).&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/encapsulation_including_classes.png&quot; alt=&quot;Encapsulation levels and design criteria in OO&quot; /&gt;
    &lt;figcaption&gt;Encapsulation levels and design criteria in OO&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Two of these new design criteria are &lt;strong&gt;class cohesion&lt;/strong&gt; and &lt;strong&gt;class coupling&lt;/strong&gt;, which are analogue to the structured programing’s procedure cohesion and procedure coupling, but, as you can see, there are other ones in the table for which there isn’t even a name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connascence&lt;/strong&gt; is meant to be a deeper criterion behind all of them and, as such, it is a general way to evaluate design decisions in an OO design. This is the formal definition of &lt;strong&gt;connascence&lt;/strong&gt; by Page-Jones:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Connascence&lt;/strong&gt; between two software elements A and B means either&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;that you can postulate some change to A that would require B to be changed (or at least carefully checked) in order to preserve overall correctness, or&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;that you can postulate some change that would require both A and B to be changed together in order to preserve overall correctness.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, there is &lt;strong&gt;connascence&lt;/strong&gt; between two software elements when they must change together in order for the software to keep working correctly.&lt;/p&gt;

&lt;p&gt;We can see how this new design criteria can be used for any of the interdependencies among encapsulation levels present in OO. Moreover, it can also be used for higher levels of encapsulation (packages, modules, components, bounded contexts, etc). In fact, according to Page-Jones, &lt;strong&gt;connascence&lt;/strong&gt; is applicable to any design paradigm with partitioning, encapsulation and visibility rules&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;3-forms-of-connascence&quot;&gt;3. Forms of connascence.&lt;/h3&gt;

&lt;p&gt;Page-Jones distinguishes several forms (or types) of &lt;strong&gt;connascence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connascence&lt;/strong&gt; can be &lt;strong&gt;static&lt;/strong&gt;, when it can be assessed from the lexical structure of the code, or &lt;strong&gt;dynamic&lt;/strong&gt;, when it depends on the execution patterns of the code at run-time.&lt;/p&gt;

&lt;p&gt;There are several types of &lt;strong&gt;static connascence&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Name&lt;/strong&gt; (CoN): when multiple components must agree on the name of an entity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Type&lt;/strong&gt; (CoT): when multiple components must agree on the type of an entity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Meaning&lt;/strong&gt; (CoM) or &lt;strong&gt;Connascence of Convention&lt;/strong&gt; (CoC): when multiple components must agree on the meaning of specific values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Position&lt;/strong&gt; (CoP): when multiple components must agree on the order of values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Algorithm&lt;/strong&gt; (CoA): when multiple components must agree on a particular algorithm.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also several types of &lt;strong&gt;dynamic connascence&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Execution&lt;/strong&gt; (order) (CoE): when the order of execution of multiple components is important.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Timing&lt;/strong&gt; (CoTm): when the timing of the execution of multiple components is important.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Value&lt;/strong&gt; (CoV): when there are constraints on the possible values some shared elements can take. It’s usually related to invariants.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Connascence of Identity&lt;/strong&gt; (CoI): when multiple components must reference the entity.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another important form of &lt;strong&gt;connascence&lt;/strong&gt; is &lt;strong&gt;contranascence&lt;/strong&gt; which exists when elements are required to differ from each other (e.g., have different name in the same namespace or be in different namespaces, etc). &lt;strong&gt;Contranascence&lt;/strong&gt; may also be either static or a dynamic.&lt;/p&gt;

&lt;h3 id=&quot;4-properties-of-connascence&quot;&gt;4. Properties of connascence.&lt;/h3&gt;

&lt;p&gt;Page-Jones talks about two important properties of &lt;strong&gt;connascence&lt;/strong&gt; that help measure its impact on maintanability:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Degree of explicitness&lt;/strong&gt;: the more explicit a &lt;strong&gt;connascence&lt;/strong&gt; form is, the weaker it is.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Locality&lt;/strong&gt;: &lt;strong&gt;connascence&lt;/strong&gt; across encapsulation boundaries is much worse than &lt;strong&gt;connascence&lt;/strong&gt; between elements inside the same encapsulation boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A nice way to reformulate this is using what it’s called the &lt;strong&gt;three axes of connascence&lt;/strong&gt;&lt;a href=&quot;#nota3&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;h4 id=&quot;41-degree&quot;&gt;4.1. Degree.&lt;/h4&gt;
&lt;p&gt;The degree of an instance of &lt;strong&gt;connascence&lt;/strong&gt; is related to the size of its impact. For instance, a software element that is connascent with hundreds of elements is likely to become a larger problem than one that is connascent to only a few.&lt;/p&gt;

&lt;h4 id=&quot;42-locality&quot;&gt;4.2 Locality.&lt;/h4&gt;
&lt;p&gt;The locality of an instance of &lt;strong&gt;connascence&lt;/strong&gt; talks about how close the two software elements are to each other. Elements that are close together (in the same encapsulation boundary) should typically present more, and higher forms of &lt;strong&gt;connascence&lt;/strong&gt; than elements that are far apart (in different encapsulation boundaries). In other words, as the distance between software elements increases, the forms of &lt;strong&gt;connascence&lt;/strong&gt; should be weaker.&lt;/p&gt;

&lt;h4 id=&quot;43-stregth&quot;&gt;4.3 Stregth.&lt;/h4&gt;
&lt;p&gt;Page-Jones states that &lt;strong&gt;connascence&lt;/strong&gt; has a spectrum of explicitness. The more implicit a form of &lt;strong&gt;connascence&lt;/strong&gt; is, the more time consuming and costly it is to detect. Also a stronger form of &lt;strong&gt;connascence&lt;/strong&gt; is usually harder to refactor. Following this reasoning, we have that stronger forms of &lt;strong&gt;connascence&lt;/strong&gt; are harder to detect and/or refactor. 
This is why &lt;strong&gt;static&lt;/strong&gt; forms of &lt;strong&gt;connascence&lt;/strong&gt; are weaker (easier to detect) than the &lt;strong&gt;dynamic&lt;/strong&gt; ones, or, for example, why &lt;strong&gt;CoN&lt;/strong&gt; is much weaker (easier to refactor) than &lt;strong&gt;CoP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The following figure by Kevin Rutherford shows the different forms of &lt;strong&gt;connascence&lt;/strong&gt; we saw before, but sorted by descending strength.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/connascence-o-meter.png&quot; alt=&quot;Connascence forms sorted by descending strength (from Kevin Rutherford&apos;s XP Surgery)&quot; /&gt;
    &lt;figcaption&gt;
      **connascence** forms sorted by descending strength (from &lt;a href=&quot;http://xpsurgery.eu/resources/connascence/&quot;&gt;Kevin Rutherford&apos;s XP Surgery&lt;/a&gt;).
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;5-connascence-design-principles-and-refactoring&quot;&gt;5. Connascence, design principles and refactoring.&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connascence&lt;/strong&gt; is simpler than other design principles, such as, the SOLID principles, Law of Demeter, etc. In fact, it can be used to see those principles in a different light, as they can be seen using more fundamental principles like the ones in the first chapter of &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt;’s &lt;a href=&quot;https://www.amazon.com/Implementation-Patterns-Kent-Beck/dp/0321413091&quot;&gt;Implementation Patterns&lt;/a&gt; book.&lt;/p&gt;

&lt;p&gt;We use &lt;strong&gt;code smells&lt;/strong&gt;, which are a collection of code quality antipatterns, to guide our refactorings and improve our design, but, according to Kevin Rutherford, they are not the ideal tool for this task&lt;a href=&quot;#nota4&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;. Sometimes &lt;strong&gt;connascence&lt;/strong&gt; might be a better metric to reason about coupling than the somewhat fuzzy concept of code smells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connascence&lt;/strong&gt; gives us a &lt;strong&gt;more precise vocabulary&lt;/strong&gt; to talk and reason about &lt;strong&gt;coupling and cohesion&lt;/strong&gt;&lt;a href=&quot;#nota5&quot;&gt;&lt;sup&gt;[5]&lt;/sup&gt;&lt;/a&gt;, and thus helps us to better judge our designs in terms of coupling and cohesion, and decide how to improve them. In words of &lt;a href=&quot;http://practicingruby.com/articles/connascence&quot;&gt;Gregory Brown&lt;/a&gt;, “this allows us to be much more specific about the problems we’re dealing with, which makes it it easier to reason about the types of refactorings that can be used to weaken the connascence between components”.&lt;/p&gt;

&lt;p&gt;It provides a classification of forms of coupling in a system, and even better, a scale of the relative strength of the coupling each form of &lt;strong&gt;connascence&lt;/strong&gt; generates. It’s precisely that scale of relative strengths what makes &lt;strong&gt;connascence&lt;/strong&gt; a much better guide for refactoring. As Kevin Rutherford says:&lt;/p&gt;
&lt;blockquote&gt;
&quot;because it classifies the relative strength of that coupling, connascence can be used as a tool to help prioritize what should be refactored first&quot;
&lt;/blockquote&gt;

&lt;p&gt;Connascence explains why doing a given refactoring is a good idea.&lt;/p&gt;

&lt;h3 id=&quot;6-how-should-we-apply-connascence&quot;&gt;6. How should we apply connascence?&lt;/h3&gt;

&lt;p&gt;Page-Jones offers three guidelines for using &lt;strong&gt;connascence&lt;/strong&gt; to improve systems maintanability:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Minimize overall &lt;strong&gt;connascence&lt;/strong&gt; by breaking the system into encapsulated elements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Minimize any remaining &lt;strong&gt;connascence&lt;/strong&gt; that crosses encapsulation boundaries.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Maximize the &lt;strong&gt;connascence&lt;/strong&gt; within encapsulation boundaries.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;According to Kevin Rutherford, the first two points conforms what he calls &lt;strong&gt;the Page-Jones refactoring algorithm&lt;/strong&gt;&lt;a href=&quot;#nota6&quot;&gt;&lt;sup&gt;[6]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These guidelines generalize the structured design ideals of &lt;strong&gt;low coupling and high cohesion&lt;/strong&gt; and is applicable to OO, or, as it was said before, to any other paradigm with partitioning, encapsulation and visibility rules.&lt;/p&gt;

&lt;p&gt;They might still be a little subjective, so some of us, prefer a more concrete way to apply &lt;strong&gt;connascence&lt;/strong&gt; using, Jim Weirich’s two principles or rules:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Rule of Degree&lt;/strong&gt;&lt;a href=&quot;#nota7&quot;&gt;&lt;sup&gt;[7]&lt;/sup&gt;&lt;/a&gt;: Convert strong forms of &lt;strong&gt;connascence&lt;/strong&gt; into weaker forms of connascence.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Rule of Locality&lt;/strong&gt;: As the distance between software elements increases, use weaker forms of connascence.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;7-whats-next&quot;&gt;7. What’s next?&lt;/h3&gt;

&lt;p&gt;In future posts, we’ll see examples of concrete forms of &lt;strong&gt;conasscence&lt;/strong&gt; relating them with design principles, code smells, and refactorings that might improve the design.&lt;/p&gt;

&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] See Kevin Rutherford&apos;s great post &lt;a href=&quot;https://silkandspinach.net/2012/09/03/the-problem-with-code-smells/&quot;&gt;The problem with code smells&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] This explains the titles Jim Weirich chose for his talks: &lt;a href=&quot;https://www.youtube.com/watch?time_continue=2890&amp;amp;v=NLT7Qcn_PmI&quot;&gt;Grand Unified Theory of Software Design&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=l780SYuz9DI&quot;&gt;The Building Blocks of Modularity&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota3&quot;&gt;&lt;/a&gt; [3] See the webinar &lt;a href=&quot;https://www.youtube.com/watch?v=L727roWRfFg&quot;&gt;Connascence: How to Measure Coupling&lt;/a&gt; by &lt;a href=&quot;https://www.linkedin.com/in/nickhodges&quot;&gt;Nick Hodges&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota4&quot;&gt;&lt;/a&gt; [4] Again see Kevin Rutherford&apos;s great post &lt;a href=&quot;https://silkandspinach.net/2012/09/03/the-problem-with-code-smells/&quot;&gt;The problem with code smells&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota5&quot;&gt;&lt;/a&gt; [5] The concepts of coupling and cohesion can be hard to grasp, just see this debate about them 
  &lt;a href=&quot;https://www.youtube.com/watch?v=hd0v72pD1MI&quot;&gt;Understanding Coupling and Cohesion hangout&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota6&quot;&gt;&lt;/a&gt; [6] See Kevin Rutherford&apos;s post &lt;a href=&quot;https://silkandspinach.net/2016/06/09/the-page-jones-refactoring-algorithm/&quot;&gt;The Page-Jones refactoring algorithm&lt;/a&gt;.
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;a name=&quot;nota7&quot;&gt;&lt;/a&gt; [7] Even though he used the word &lt;strong&gt;degree&lt;/strong&gt;, he was actually talking about &lt;strong&gt;strength&lt;/strong&gt;.
&lt;/div&gt;

&lt;h3 id=&quot;references&quot;&gt;References.&lt;/h3&gt;
&lt;h4 id=&quot;books&quot;&gt;Books.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Fundamentals-Object-Oriented-Design-Meilir-Page-Jones/dp/020169946X/ref=asap_bc?ie=UTF8&quot;&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt;, Meilir Page-Jones&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Every-Programmer-Should-Object-Oriented-Design/dp/0932633315&quot;&gt;What every programmer should know about object-oriented design&lt;/a&gt;, Meilir Page-Jones&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.goodreads.com/book/show/946145.Structured_Design&quot;&gt;Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design&lt;/a&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Edward_Yourdon&quot;&gt;Edward Yourdon&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Larry_Constantine&quot;&gt;Larry L. Constantine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;papers&quot;&gt;Papers.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.cfcl.com/pub/Projects/Connascence/Resources/p147-page-jones.pdf&quot;&gt;Comparing Techniques by Means of Encapsulation and Connascence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;talks&quot;&gt;Talks.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=l780SYuz9DI&quot;&gt;The Building Blocks of Modularity&lt;/a&gt;, Jim Weirich (&lt;a href=&quot;http://www.slideshare.net/LittleBIGRuby/the-building-blocks-of-modularity&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?time_continue=2890&amp;amp;v=NLT7Qcn_PmI&quot;&gt;Grand Unified Theory of Software Design&lt;/a&gt;, Jim Weirich (&lt;a href=&quot;https://github.com/jimweirich/presentation_connascence/blob/master/Connascence.key.pdf&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://yow.eventer.com/yow-2012-1012/connascence-examined-by-jim-weirich-1273&quot;&gt;Connascence Examined&lt;/a&gt;, Jim Weirich&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HQXVKHoUQxY&quot;&gt;Connascence Examined (newer version, it goes into considerable detail of the various types of connascence)&lt;/a&gt;, Jim Weirich (&lt;a href=&quot;https://github.com/jimweirich/presentation-connascence-examined/blob/master/pdf/connascence_examined.key.pdf&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hd0v72pD1MI&quot;&gt;Understanding Coupling and Cohesion hangout&lt;/a&gt;, Corey Haines, Curtis Cooley, Dale Emery, J. B. Rainsberger, Jim Weirich, Kent Beck, Nat Pryce, Ron Jeffries.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=fSr8LDcb0Y0﻿&quot;&gt;Red, Green, … now what ?!&lt;/a&gt;, Kevin Rutherford (&lt;a href=&quot;http://xpsurgery.eu/resources/connascence-hunt-slides/&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2016/12/charla-sobre-connascence-en-scbcn16&quot;&gt;Connascence&lt;/a&gt;, Fran Reyes y Alfredo Casado (&lt;a href=&quot;http://slides.com/franreyesperdomo/connascence#/&quot;&gt;slides&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=L727roWRfFg&quot;&gt;Connascence: How to Measure Coupling&lt;/a&gt;, Nick Hodges&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;posts&quot;&gt;Posts.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://practicingruby.com/articles/connascence&quot;&gt;Connascence as a Software Design Metric&lt;/a&gt;, by Gregory Brown.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://silkandspinach.net/2012/09/03/the-problem-with-code-smells/&quot;&gt;The problem with code smells&lt;/a&gt;, Kevin Rutherford&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://silkandspinach.net/2014/09/19/a-problem-with-primitive-obsession/&quot;&gt;A problem with Primitive Obsession&lt;/a&gt;, Kevin Rutherford&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://silkandspinach.net/2016/06/09/the-page-jones-refactoring-algorithm/&quot;&gt;The Page-Jones refactoring algorithm&lt;/a&gt;, Kevin Rutherford&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.markhneedham.com/blog/2009/10/28/coding-connascence-some-examples/&quot;&gt;Connascence – Some examples&lt;/a&gt;, Mark Needham&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;others&quot;&gt;Others.&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://connascence.io&quot;&gt;Connascence.io&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Connascence_(computer_programming)&quot;&gt;Connascence at Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2017-01-20T07:15:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/about-connascence</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/about-connascence</guid>
        </item>
      
    
      
        <item>
          <title>Podemos ser tu equipo</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/equipo.jpg&quot; alt=&quot;nuestro equipo casi al completo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Todo el mundo está a la búsqueda de desarrolladores, todos al grito de “we’re hiring!”. Quizás estemos viviendo otra gran burbuja del sector TIC. A las empresas les está costando encontrar y retener talento. Sobre todo, les está
costando ensamblar equipos.&lt;/p&gt;

&lt;p&gt;El desarrollo de software es un deporte de equipo. Es más importante que las personas trabajen bien en equipo que tener genios individualistas resolutivos en el corto plazo. Sobre todo porque el coste del software se puede disparar con el paso del tiempo debido al mantenimiento y lo que hoy se hace demasiado rápido, mañana se paga con intereses. A menudo se calcula el coste del software contando sólo las horas que lleva poner en producción la primera versión usable, pero en realidad ese coste es pequeño comparado con el de mantener el software, darle soporte y continuidad.
El cuello de botella de los proyectos no está en la velocidad con la que añadimos líneas de código, sino en la complejidad innecesaria que generamos. Esta complejidad muchas veces tiene su origen en una mala definición de requisitos por no haber entendido bien el problema que se pretende solucionar. Otras veces se debe a no conocer prácticas y técnicas que ayudan a mantener tu código habitable y fácil de adaptar al cambio.&lt;/p&gt;

&lt;p&gt;Por si esto fuera poco, como empleadores, contratar nos parece un gran compromiso. Los proyectos a menudo son de unos pocos meses y uno no quiere tener que despedir a una persona al poco tiempo de haber sido contratada.&lt;/p&gt;

&lt;p&gt;Aún consiguiendo reunir un grupo adecuado, las personas que no han trabajado nunca juntas necesitan un tiempo de adaptación para conocerse y conseguir un buen “flow”. La productividad es mayor cuando las personas están acostumbradas a trabajar juntas. Además se necesita tiempo para familiarizarse con las convenciones del equipo, las dinámicas, las herramientas…&lt;/p&gt;

&lt;p&gt;Por todo esto, si estratégicamente lo prioritario en tu caso no es formar un equipo, sino simplemente avanzar ya y con calidad en el desarrollo de producto, nosotros podemos ayudarte.&lt;/p&gt;

&lt;p&gt;Podemos ser tu equipo, con todas las ventajas que proporciona un equipo de alto rendimiento con el que la colaboración es igual de cercana, intensa y comprometida que si fuesen tus empleados.&lt;/p&gt;

&lt;p&gt;Y podemos ofrecerte otro servicio más, si llega un momento en el que necesitas que el software lo evolucionen otras personas, las incorporaremos progresivamente, para transmitirles el conocimiento técnico del producto y nuestros valores y prácticas.&lt;/p&gt;

&lt;p&gt;Quizás es una opción que nunca habías valorado, ¿quieres que Codesai sea tu equipo de desarrollo?&lt;/p&gt;
</description>
          <pubDate>2017-01-18T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/podemos-ser-tu-equipo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/podemos-ser-tu-equipo</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre distinguir entre problema y solución en la CAS2016</title>
          <description>&lt;p&gt;En &lt;a href=&quot;http://cas2016.agile-spain.org/&quot;&gt;la pasada CAS 2016&lt;/a&gt; di un charla sobre aprender a distinguir entre el problema y solución.&lt;/p&gt;

&lt;p&gt;Esta distinción es importante porque uno de los motivos por los que más se desperdicia código, tiempo y dinero, es que confundimos la solución con el problema. No entendemos bien el problema del usuario y nos equivocamos al tomar requisitos.&lt;/p&gt;

&lt;p&gt;Esto nos produce la sensación de que el cliente está todo el tiempo cambiando de opinión y de que los requisitos son supervolátiles, pero en muchas ocasiones no es así. Es la comunicación la que falla.&lt;/p&gt;

&lt;p&gt;Es normal porque estamos entrenados para buscar soluciones, los desarrolladores somos “solucionólogos”.&lt;/p&gt;

&lt;p&gt;Al elegir una solución concreta estamos descartando todas las demás. Si había otras más sencillas y/o convenientes para resolver el mismo problema, ya no nos daremos cuenta nunca, o quizás, lo haremos cuando ya sea demasiado tarde, después de dar demasiadas vueltas.&lt;/p&gt;

&lt;p&gt;Creo que ser capaces de distinguir mejor entre problema y solución, es decir, separar lo mejor posible el &lt;strong&gt;“Qué”&lt;/strong&gt; del &lt;strong&gt;“Cómo”&lt;/strong&gt;, nos hace más eficaces y económicos a la hora de solucionar problemas, sin perjudicar la calidad de las soluciones, y por tanto nos hace más ágiles.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/problem_solution_talk_sketch.jpeg&quot; alt=&quot;charla Carlos&quot; /&gt;
    &lt;figcaption&gt;Sketch notes de la charla&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Este es el video de mi charla &lt;strong&gt;Distinguir entre Problema y Solución&lt;/strong&gt; que han publicado recientemente nuestros buenos amigos de &lt;a href=&quot;https://www.autentia.com/&quot;&gt;Autentia&lt;/a&gt;&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;IqUo9kCWQrw&quot;&gt;
    &lt;div data-id=&quot;IqUo9kCWQrw&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/IqUo9kCWQrw/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Y estas son las slides de la charla:&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/4IHtiPuupOukIP&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
   &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] ¡Muchas gracias Aitor!   
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
   &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] ¡Muchas gracias Autentia!   
&lt;/div&gt;
</description>
          <pubDate>2017-01-13T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/charla-aprender-distinguir-problema-soluciones-en-cas2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/charla-aprender-distinguir-problema-soluciones-en-cas2016</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre el camino del aprendizaje en la CAS2016</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/charla_ronny_modesto_1.jpeg&quot; alt=&quot;Ronny y Modesto comenzando su charla&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En una profesión como la nuestra en la que cada mes tenemos nuevas tecnologías, metodologías, prácticas… sería un grave error caer en el conformismo o pensar que hemos llegado a la cima de nuestro aprendizaje.&lt;/p&gt;

&lt;p&gt;Tal y como plantea el &lt;a href=&quot;http://chimera.labs.oreilly.com/books/1234000001813/index.html&quot;&gt;libro Apprenticeship Patterns&lt;/a&gt;, el camino del aprendizaje es infinito. Como aprendices nunca nos veremos alcanzar la maestría, pero somos conscientes de que el aprendizaje continuo marca una gran diferencia. Creemos que aprender de manera constante es indispensable para asegurar la calidad de nuestro trabajo. Asimismo, consideramos que es esencial entender cómo aprendemos, de manera que, nos permita ser más eficaces a la hora de adquirir nuevos conocimientos o profundizar en otros.&lt;/p&gt;

&lt;p&gt;Esta charla, que &lt;a href=&quot;https://twitter.com/msanjuan?lang=en&quot;&gt;Modesto&lt;/a&gt; y yo presentamos en &lt;a href=&quot;http://cas2016.agile-spain.org/&quot;&gt;la pasada CAS 2016&lt;/a&gt;, trata principalmente de resumir cómo aprendemos y qué mecanismos podemos utilizar en nuestro día día para mejorar, aprender y compartir tanto dentro como fuera de nuestro trabajo.&lt;/p&gt;

&lt;p&gt;Ha sido muy emocionante poder aportar nuestro pequeño grano de arena a la CAS 2016. Fue todo un eventazo y nos gustaría dar las gracias a todos los participantes y organizadores que la han hecho posible. También queremos agradecer todo el feedback que recibimos sobre nuesta charla.&lt;/p&gt;

&lt;p&gt;Este es el video de la charla publicado recientemente por nuestros amigos de &lt;a href=&quot;https://www.autentia.com/&quot;&gt;Autentia&lt;/a&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;azVsa8XQp8c&quot;&gt;
    &lt;div data-id=&quot;azVsa8XQp8c&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/azVsa8XQp8c/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
   &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] ¡Muchas gracias!   
&lt;/div&gt;
</description>
          <pubDate>2017-01-05T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/charla-camino-aprendizaje-cas2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/charla-camino-aprendizaje-cas2016</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre funciones en Clojure</title>
          <description>&lt;p&gt;Hace unas semanas hicimos nuestro segunda charla remota sobre Clojure como parte de las actividades que hacemos en nuestro pequeño grupo de estudio de Clojure/ClojureScript.&lt;/p&gt;

&lt;p&gt;Esta vez profundizamos en las diferentes maneras de definir funciones.&lt;/p&gt;

&lt;p&gt;Aquí les comparto la grabación de la charla:&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;HmAU-z5dPS8&quot;&gt;
    &lt;div data-id=&quot;HmAU-z5dPS8&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/HmAU-z5dPS8/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;y aquí pueden encontrar &lt;a href=&quot;https://gist.github.com/trikitrok/b14d12f78113ad8494fc&quot;&gt;los ejemplos que usamos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez más, me gustaría darle las gracias a &lt;a href=&quot;https://twitter.com/rojo_angel&quot;&gt;Ángel&lt;/a&gt; y a &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento&lt;/a&gt; Barcelona por dejarnos grabar la charla en sus oficinas.&lt;/p&gt;

&lt;p&gt;Espero que les resulte útil.&lt;/p&gt;
</description>
          <pubDate>2017-01-04T00:08:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/charla-clojure-functions</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/charla-clojure-functions</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre Comunidades de Necesidad vs Comunidades de Soluciones en la CAS2016</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/charla_antonio.jpg&quot; alt=&quot;charla antonio&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El pasado 30 de noviembre cogí un avión a las 7 de la mañana para ir a Vitoria. Pocas veces me costó tan poco madrugar porque sabía que me esperaba un evento delicioso. Las expectativas eran altas sabiendo que detrás estaban los de &lt;a href=&quot;https://www.meetup.com/AgileNorte/&quot;&gt;Agile Norte&lt;/a&gt;. Y se cumplieron.&lt;/p&gt;

&lt;p&gt;Agradezco enormemente que mi charla hubiese sido elegida, porque se que la selección es muy complicada, muchas a escoger y acertar solo con la descripción es difícil.&lt;/p&gt;

&lt;p&gt;Mi sesión, titulada “Comunidades de Necesidad vs Comunidades de Soluciones”, tiene su origen en la &lt;a href=&quot;http://ale2015.eu/&quot;&gt;ALE de 2015&lt;/a&gt; celebrada en Sofía hace dos veranos, donde en la keynote inaugural introdujo este tema &lt;a href=&quot;https://twitter.com/PapaChrisMatts&quot;&gt;Chris Matts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Me hizo ver que dividimos constantemente los problemas y las personas en dos tipos, los que van a la última y los pragmáticos, muchas veces sin tener en cuenta el problema y únicamente nuestro propio interés.&lt;/p&gt;

&lt;p&gt;Desde ahí, elaboré esta sesión basándome en los posts que escribió Chris para preparar la keynote&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt; que me dió un conocimiento mucho más profundo de lo que significa tener opciones antes de decidir.&lt;/p&gt;

&lt;p&gt;Mi exposición es un viaje usando el &lt;a href=&quot;https://en.wikipedia.org/wiki/Crossing_the_Chasm&quot;&gt;Crossing the Chasm&lt;/a&gt; como vehículo para conocer conceptos como ver la necesidad, explorar opciones, probar nuevos contextos, distinguir escenarios de buenas prácticas de otros de prueba y error, valorar las opciones hasta el último momento responsable, principios y prácticas, y vender las mejores soluciones encontradas.&lt;/p&gt;

&lt;p&gt;Y si solo te tuvieras que llevar una idea sería esta:&lt;/p&gt;

&lt;blockquote&gt;
&quot;Si las soluciones encontradas se basan más en los los principios que las crearon que en un conjunto de buenas prácticas, entonces enseñarlas como una receta a aplicar conducirá directo al fracaso. Porque cuando salgan escenarios no contemplados previamente, que saldrán, no sabremos cómo actuar.&quot;
&lt;/blockquote&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/charla_antonio_esquema.jpg&quot; alt=&quot;charla antonio&quot; /&gt;
    &lt;figcaption&gt;Sketch notes de la charla&lt;a href=&quot;#nota2&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Los amigos de &lt;a href=&quot;https://www.autentia.com/&quot;&gt;Autentia&lt;/a&gt; acaban de publicar el video de la charla. Gracias!&lt;/p&gt;

&lt;p&gt;Al inicio hago un pequeño y emotivo homenaje a la comunidad agile.&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;jzV7pMshyic&quot;&gt;
    &lt;div data-id=&quot;jzV7pMshyic&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/jzV7pMshyic/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Y aquí tenéis las slides que utilizamos en la charla:&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;https://www.slideshare.net/slideshow/embed_code/key/kA06DFrC4s748U&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Y al final como siempre saber balancear es la clave de todo.&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
   &lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt; [1] Referencias:
   &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://theitriskmanager.wordpress.com/2015/04/19/communities-of-need-community-of-solutions/&quot;&gt;Communities of Need &amp;amp; Community of Solutions&lt;/a&gt;&lt;/li&gt;

    &lt;li&gt;&lt;a href=&quot;https://theitriskmanager.wordpress.com/2015/05/05/agile-the-broken-learning-machine/&quot;&gt;Agile – The Broken Learning Machine&lt;/a&gt;&lt;/li&gt;

    &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=QCtMh4tMCRE&quot;&gt;Agile - The Broken Learning Machine - ALE 2015 keynote&lt;/a&gt;&lt;/li&gt;
   &lt;/ul&gt;
&lt;/div&gt;

&lt;div class=&quot;foot-note&quot;&gt;
   &lt;a name=&quot;nota2&quot;&gt;&lt;/a&gt; [2] Tomadas por el gran &lt;a href=&quot;https://twitter.com/oyabun?lang=en&quot;&gt;Javier Alonso (@oyabun)&lt;/a&gt;. Muchísimas gracias por tu fantástico trabajo.
&lt;/div&gt;
</description>
          <pubDate>2017-01-03T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/charla-sobre-comunidades-de-necesidad-vs-comunidades-de-soluciones-en-la-cas2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/charla-sobre-comunidades-de-necesidad-vs-comunidades-de-soluciones-en-la-cas2016</guid>
        </item>
      
    
      
        <item>
          <title>ES6 en React y resolviendo el binding del this</title>
          <description>&lt;p&gt;Estás últimas semanas he estado aprendiendo &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; para un &lt;a href=&quot;https://github.com/AIDAsoftware/Papyrus&quot;&gt;pet project&lt;/a&gt; que estoy haciendo con mis compañeros &lt;a href=&quot;https://twitter.com/ronnyancorini&quot;&gt;Ronny&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/msanjuan&quot;&gt;Modesto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tiramos lo que teníamos de nuestra interfaz hecha con &lt;a href=&quot;https://www.polymer-project.org&quot;&gt;Polymer&lt;/a&gt; (que no era mucho tampoco) puesto que nos veíamos incapaces de avanzar de una forma constante ya que nos encontrábamos con problemas a cada momento que decidíamos sentarnos a programar.&lt;/p&gt;

&lt;p&gt;Otro motivo para desechar Polymer es que testearlo se nos hacía un poco complicado. Además no nos terminaba de encajar el modelo que Google propone para testear el comportamiento de tu componente empleando la librería de Node.js llamada &lt;a href=&quot;https://github.com/Polymer/web-component-tester&quot;&gt;web-component-tester&lt;/a&gt;. Lo malo es que al ejecutar los tests, web-component-tester necesita lanzar una instancia de &lt;a href=&quot;http://www.seleniumhq.org/projects/webdriver/&quot;&gt;Webdriver&lt;/a&gt; para correr Google Chrome y probar la lógica que quieras probar. Esto nos complica también el hecho de que si quisieramos lanzar los test en un entorno de integración continua, no podríamos ni siquiera usando &lt;a href=&quot;http://phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt; pues aún no soporta el estándar de &lt;a href=&quot;http://webcomponents.org/&quot;&gt;Web Components&lt;/a&gt; en el que Polymer se basa.&lt;/p&gt;

&lt;p&gt;Estas y varias otras razones (compatibilidad con múltiples navegadores, mayor cantidad de documentación y un maravilloso &lt;a href=&quot;https://app.pluralsight.com/library/courses/react-flux-building-applications/&quot;&gt;curso de introducción&lt;/a&gt; de &lt;a href=&quot;https://twitter.com/housecor&quot;&gt;Corey House&lt;/a&gt; en &lt;a href=&quot;https://www.pluralsight.com/&quot;&gt;Pluralsight&lt;/a&gt;) nos hicieron decantarnos por React.js para fabricar la interfaz web de nuestra aplicación.&lt;/p&gt;

&lt;p&gt;En este post quisiera hablar en concreto de dos decisiones que hemos tomado durante el desarrollo:&lt;/p&gt;

&lt;p&gt;La primera fue &lt;em&gt;usar &lt;a href=&quot;http://es6-features.org/&quot;&gt;ECMAScript 6&lt;/a&gt; en el proyecto&lt;/em&gt;. Preferimos ES6 porque no tiene mucho sentido seguir usando ES5 a día de hoy, puesto que ES6 es el estándar.&lt;/p&gt;

&lt;p&gt;De entre los approaches que hemos seguido para crear componentes en React, al final hemos optado por emplear las clases de ES6. Aunque no nos parece una solución completamente limpia y nos gusta más el enfoque de usar únicamente funciones en JavaScript, nos parece mejor que usar el React.createClass pasándole el objeto que contiene la definición de nuestras funciones dentro del componente o usar meramente composición. La razón es que abstraernos de la librería nos parecía demasiado esfuerzo para acabar con una solución demasiado compleja.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/1bb99309aab0cc1063e5ca2bceaf0324.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Aquí tenemos un ejemplo de componente que hemos creado con React. Como vemos es tan sencillo como crear una clase y extender de &lt;a href=&quot;https://facebook.github.io/react/docs/react-component.html&quot;&gt;React.Component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La decisión que tomamos tiene varias implicaciones, lo cual nos lleva a nuestra segunda decisión. &lt;em&gt;Decidir cuál es el mecanismo para hacer el binding del this&lt;/em&gt; cuando la función &lt;a href=&quot;https://facebook.github.io/react/docs/two-way-binding-helpers.html&quot;&gt;this.handleChange&lt;/a&gt; es pasada como callback a un componente hijo.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/c26dbcccfb47a602e35cec7e63089970.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Si nos fijamos en el render, al pasarle la función que tenemos asociada en nuestra clase al &lt;a href=&quot;https://facebook.github.io/react/docs/forms.html&quot;&gt;onChange&lt;/a&gt;, lo que ocurre básicamente es que JavaScript no liga el this que usa la función internamente al de la instancia de la clase que pasa esa función. Para resolver esta situación hemos encontrado diversas soluciones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Usar el React.createClass&lt;/strong&gt;. Si empleamos la función que nos provee React para crear componentes, esta internamente hará toda la magia por nosotros. &lt;strong&gt;Usar el bind&lt;/strong&gt; cuando pasemos nuestra función como callback al componente hijo: &lt;em&gt;“onChange={this.handleChange.bind(this)}”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pasarle un &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;Arrow Function&lt;/a&gt;&lt;/strong&gt; con la llamada al método en onChange: &lt;em&gt;“onChange={ value =&amp;gt; { this.handleChange(value) }}&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Declarar handleChange dentro del constructor empleando un Arrow Function&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/296251f77a8fd7b42699f07071235949.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Estas son las tres maneras más sencillas de resolver nuestro problema sin tener que recurrir a mecanismos externos. Sin embargo, ninguna de ellas nos gustaba, y en caso de tener que adoptar alguna de las tres últimas, preferiríamos optar por emplear React.createClass.&lt;/p&gt;

&lt;p&gt;Buscando otras formas de resolver este problema, encontramos un mecanismo que está por implementar en la siguiente especificación del lenguaje (ES2016), que básicamente es el &lt;strong&gt;emplear un decorador de función&lt;/strong&gt; para que te haga el binding automáticamente empleando la librería “&lt;a href=&quot;https://www.npmjs.com/package/autobind-decorator&quot;&gt;autobind-decorator&lt;/a&gt;” disponible en NPM. El resultado final sería algo tal que así:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/f829351fe0e9b85d5fc8bb26cd79b5ef.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Esta opción tampoco nos acababa de convencer, &lt;strong&gt;dado que tenemos que estar importando en cada componente la librería de autobind&lt;/strong&gt; y no nos parece un solución lo suficientemente limpia como para tenerla en consideración. Una cosa a tener en cuenta para usar este mecanismo, en caso de estar usando &lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel 6&lt;/a&gt; para transpilar, debes utilizar también el preset “babel-plugin-transform-decorators-legacy” para que funcione adecuadamente (todo está explicando en su Github de todas maneras).&lt;/p&gt;

&lt;p&gt;La opción que al final elegimos fue la última: &lt;strong&gt;emplear una &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;Arrow Function&lt;/a&gt; en una propiedad de la clase&lt;/strong&gt;. El problema con el que nos encontramos al usar esta solución, es que la especificación actual del lenguaje no soporta esta característica. Hay dos formas de lograr que funcione. La primera es usar el plugin de Babel “transform-class-properties” y la segunda es establecer el preset “stage-2” de Babel instalando “babel-preset-stage-2” en NPM. Al final, todo quedaría de la siguiente forma:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/f4b664d4843dd5080bfcaf9683b849dc.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Un último detalle a tener en cuenta al usar esta solución y el autobind, es que dado que nosotros usamos &lt;a href=&quot;http://eslint.org/&quot;&gt;eslint&lt;/a&gt;, tenemos que configurarlo para que soporte ambas features. Para arreglarlo, basta con únicamente usar “babel-eslint” como parser del eslinter y añadir en nuestro .babelrc lo siguiente:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Groxalf/2706ac8504cf322ba441667a51dc789e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Y listo, con eso, ya estaría todo solucionado.&lt;/p&gt;

&lt;p&gt;Esta alternativa es, desde nuestro punto de vista, la que menor ruido genera, y a nivel de legibilidad, la más simple. Al final, una simple &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;Arrow Function&lt;/a&gt; conserva el binding del this en el enclosing scope, por lo que todo se hace forma automática y se asemeja a lo que ya estamos acostumbrados en ES6.&lt;/p&gt;

&lt;p&gt;Cualquier clase de feedback será bien recibido. Aquí dejo unos enlaces que podrían ser de interés. Un saludo!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://app.pluralsight.com/author/cory-house&quot;&gt;Perfil PluralSight Corey House&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@housecor/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56#.mwn7jh38i&quot;&gt;React Binding Patterns: 5 Approaches for Handling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2017-01-02T14:30:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/es6-en-react-y-resolviendo-el-binding-del-this</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/es6-en-react-y-resolviendo-el-binding-del-this</guid>
        </item>
      
    
      
        <item>
          <title>An example of introducing symmetry to enable duplication removal</title>
          <description>&lt;p&gt;
  Symmetry is a subtle concept that may seem only related to code aesthetics.
  However, as &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; states in &lt;a href=&quot;https://www.amazon.com/Implementation-Patterns-Kent-Beck/dp/0321413091&quot;&gt;Implementation Patterns&lt;/a&gt;, 
&lt;/p&gt;

&lt;blockquote&gt;
&quot;...finding and expressing symmetry is a preliminary step to removing duplication. If a similar thought exists in several places in the code, making them symmetrical to each other is a first good step towards unifying them&quot;&lt;/blockquote&gt;

&lt;p&gt;
  In this post we&apos;ll look at an example of expressing symmetry as a way to make duplication more visible. This is the initial code of a version of &lt;a href=&quot;https://gist.github.com/trikitrok/7daea817f7d5c92776d18a6a3ddafad1&quot;&gt;a subset of the Mars Rover kata&lt;/a&gt; that &lt;a href=&quot;https://twitter.com/alvarobiz&quot;&gt;Álvaro García&lt;/a&gt; and I used in a refactoring workshop some time ago:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2ea763f0964278f9e1714e2e1cc12d31.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  This code is using conditionals to express two consecutive decisions:
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt; Which command to execute depending on a command code.&lt;/li&gt;
  &lt;li&gt; How to execute the command depending on the direction the rover faces.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
  These decisions are repeated for different responsibilities, displacing the rover and rotating the rover, so the code presents a &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=10&quot;&gt;Case Statements smell&lt;/a&gt;.
  Since those decisions are completely independent, we could mechanically refactor the code to start using polymorphism instead of conditionals. This way we&apos;ll end having two consecutive single dispatches, one for each decision.
&lt;/p&gt;

&lt;p&gt;
  If we start applying &lt;a href=&quot;http://refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html&quot;&gt;Replace Type Code with State/Strategy refactoring&lt;/a&gt; to the code as it is now, there is a subtle problem, though.
&lt;/p&gt;

&lt;p&gt;
  Looking carefully more carefully, we can observe that in the case of the rover&apos;s displacement, the sequence of two decisions is clearly there:
&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/movement_code.svg&quot; alt=&quot;Two decisions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;
  However, that sequence is not there in the case of the rover&apos;s rotations. In this case there&apos;s a third decision (conditional) based on the command type which as, we&apos;ll see, is not necessary:
&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/rotation_code.svg&quot; alt=&quot;Three decisions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;
  This difference between the two sequences of decisions reveals a lack of symmetry in the code.
  It&apos;s important to remove it before starting to refactor the code to substitute the conditionals with polymorphism. 
&lt;/p&gt;

&lt;p&gt;
  I&apos;ve seen many cases in which developers naively start extracting methods and substituting the conditionals with polymorphism starting from asymmetrical code like this one. This often leads them to create entangled and leaking abstractions.
&lt;/p&gt;

&lt;p&gt;
  Particularly, in this case, blindly applying &lt;a href=&quot;http://refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html&quot;&gt;Replace Type Code with State/Strategy refactoring&lt;/a&gt; to the left and right rotations can very likely lead to a solution containing code like the following:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/b00a96a86201e1ea28cd737bd55b57d9.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3048c53bd89d51f5a078a0d9a58e5b9c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  Notice how the &lt;i&gt;Direction&lt;/i&gt; class contains a decision based on the encoding of the command. To be able to take that decision, &lt;i&gt;Direction&lt;/i&gt; needs to know about the encoding, which is why it&apos;s been made public in the &lt;i&gt;Command&lt;/i&gt; class.
&lt;/p&gt;

&lt;p&gt;
  This is bad... Some knowledge about the commands encoding has leaked from the &lt;i&gt;Command&lt;/i&gt; class into the &lt;i&gt;Direction&lt;/i&gt; class. &lt;i&gt;Direction&lt;/i&gt; shouldn&apos;t be taking that decision in the first place. Neither should it know how commands are encoded. 
  Moreover, this is a decision that was already taken and doesn&apos;t need to be taken again. 
&lt;/p&gt;

&lt;p&gt;
How can we avoid this trap?
&lt;/p&gt;

&lt;p&gt;
  We should go back to the initial code and instead of mechanically applying refactoring, we should start by removing the asymmetry from the initial code.
&lt;/p&gt;

&lt;p&gt;
  You can see one way of doing it in this video:
&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;lBUmAZuXVmo&quot;&gt;
    &lt;div data-id=&quot;lBUmAZuXVmo&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/lBUmAZuXVmo/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;
  After this refactoring all cases are symmetrical (they present the same sequence of decisions)
&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/movement_code.svg&quot; alt=&quot;Two decisions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;
  We&apos;ve not only removed the asymmetry but we&apos;ve also made more explicit the case statements (&lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1400866&amp;amp;seqNum=10&quot;&gt;Case Statements smell&lt;/a&gt;) on the command encoding and the duplicated switches on the direction the rover is facing:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/17686efb46e0406e4ccfb307db8d5390.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  Now it&apos;s clear that the third decision (third nested conditional) in the original rover&apos;s rotations code was unnecessary.
&lt;/p&gt;

&lt;p&gt;
  If we start the &lt;a href=&quot;http://refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html&quot;&gt;Replace Type Code with State/Strategy refactoring&lt;/a&gt; now, it&apos;s more likely that we&apos;ll end with a code in which &lt;i&gt;Direction&lt;/i&gt; knows nothing about how the commands are encoded:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d30cecd89e0af1f1e2d0773cb17c3fe9.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  and the encoding of each command is known in only one place:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a28321142dffb3c0fa26c44eb5b54a0f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  As we said at the beginning, symmetry is a very useful concept that can help you guide refactoring. Detecting asymmetries and thinking why they happen, can help you to detect hidden duplication and, as in this case, sometimes entangled &lt;b&gt;dimensions of complexity&lt;/b&gt;&lt;a href=&quot;#nota1&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  Then, by removing those asymmetries, you can make the duplication more visible and disentangle the entangled dimensions of complexity. The only thing you need is to &lt;b&gt;be patient&lt;/b&gt; and don&apos;t start &quot;obvious&quot; refactorings before thinking a bit about symmetry.
&lt;/p&gt;

&lt;p&gt;
&lt;a name=&quot;nota1&quot;&gt;&lt;/a&gt;[1] &lt;b&gt;Dimension of Complexity&lt;/b&gt; is a term used by &lt;a href=&quot;https://twitter.com/mateuadsuara&quot;&gt;Mateu Adsuara&lt;/a&gt; in a talk at SocraCan16 to name an orthogonal functionality. In that talk he used dimensions of complexity to group the examples in his test list and help him choose the next test when doing TDD. He talked about it in these three posts: &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/18/complexity-dimensions-p1.html&quot;&gt;Complexity dimensions - FizzBuzz part I&lt;/a&gt;, &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/19/complexity-dimensions-p2.html&quot;&gt;Complexity dimensions - FizzBuzz part II&lt;/a&gt; and &lt;a href=&quot;http://mateuadsuara.github.io/8thlight/2015/08/20/complexity-dimensions-p3.html&quot;&gt;Complexity dimensions - FizzBuzz part III&lt;/a&gt;. Other names for the same concept that I&apos;ve heard are &lt;b&gt;axes of change&lt;/b&gt;, &lt;b&gt;directions of change&lt;/b&gt; or &lt;b&gt;vectors of change&lt;/b&gt;.
&lt;/p&gt;
</description>
          <pubDate>2017-01-02T00:16:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2017/01/an-example-of-introducing-symmetry-to</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2017/01/an-example-of-introducing-symmetry-to</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Gradiant</title>
          <description>&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;La semana pasada &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis Rovirosa&lt;/a&gt; y yo impartimos una formación de TDD en las oficinas de &lt;a href=&quot;https://www.gradiant.org/&quot;&gt;Gradiant&lt;/a&gt; en Vigo.&lt;/p&gt;

&lt;p&gt;Gradiant es el acrónimo en inglés del Centro Tecnolóxico de Telecomunicacións de Galicia (Galician Research and Development Center in Advanced Telecomunications) y utilizan los conocimientos y experiencia de sus profesionales de investigación para aportar valor a empresas y organizaciones mediante la transferencia de conocimiento y el diseño de productos especializados.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_vigo_gradiant_redux.jpg&quot; alt=&quot;asistentes al curso de TDD en Gradiant&quot; /&gt;&lt;/p&gt;

&lt;p&gt;La naturaleza del centro y su ubicación en &lt;a href=&quot;https://uvigo.gal/uvigo_gl/vigo/&quot;&gt;el campus de la Universidad de Vigo&lt;/a&gt; me recordó bastante a la época en que trabajé en el &lt;a href=&quot;https://www.bsc.es/&quot;&gt;BSC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Este fue el segundo &lt;a href=&quot;http://www.codesai.com/curso-de-tdd/&quot;&gt;curso de TDD de Codesai&lt;/a&gt; que imparto con Luis, y era todo un reto, debido al número de asistentes, 18 personas, y, sobretodo, a la gran variedad de tecnologías y tipos de sistemas que desarrollan, que iban desde C empotrado para procesado de señales o IOT, hasta APIs REST con node.js, pasando por diversas aplicaciones en Java, C++ o Scala.&lt;/p&gt;

&lt;p&gt;Creo que hacer los cursos en pareja es una gran ventaja. Por un lado, porque podemos atender mucho mejor, sobre todo si el grupo es numeroso, a las parejas durante las sesiones prácticas dándoles feedback y contestando sus dudas, para ayudar a que asimilen mejor los conceptos que persigue trabajar cada kata. Por otro lado, porque nos permite asumir roles diferentes, parecidos a los de conductor y navegador en pair-programming, para percibir mejor el pulso de nuestra audiencia y modular mejor nuestro mensaje. En este sentido, Luis y yo, nos complementamos bastante bien porque, al tener backgrounds bastante distintos y personalidades diferentes, podemos enriquecer tanto las explicaciones teóricas como las prácticas, con un rango de experiencias y perpectivas más amplio, lo que considero que fue muy útil, dada la diversidad del grupo.&lt;/p&gt;

&lt;p&gt;Algunos de los desarrolladores que asistieron al curso trabajaban en sistemas empotrados haciendo IOT o procesado de señales en los que cuentan con recursos muy limitados y en entornos en los que testear es bastante complicado. Para tratar de ayudarlos, aparte de responder dudas concretas y de las conversaciones de pasillo, reunimos una compilación de &lt;a href=&quot;https://gist.github.com/trikitrok/840436ea8bf0b2bb7f722f16a45ab54d&quot;&gt;recursos interesantes para hacer testing y TDD con C empotrado&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nos gustó muchísimo la experiencia de trabajar con las personas que asistieron al curso. Era un grupo muy agradable y con muchísimas ganas de aprender. Además, durante el curso, surgieron preguntas y debates muy interesantes debido a la gran diversidad de tipos de proyecto desarrollados por los asistentes.&lt;/p&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Hemos acabado reventados después de dos días intensos... Pero también motivadísimos &lt;a href=&quot;https://twitter.com/hashtag/tdd?src=hash&quot;&gt;#tdd&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/craftmanship?src=hash&quot;&gt;#craftmanship&lt;/a&gt; &lt;a href=&quot;https://t.co/eXtEBVssmZ&quot;&gt;https://t.co/eXtEBVssmZ&lt;/a&gt;&lt;/p&gt;&amp;mdash; Javi Sánchez Rois (@jsrois) &lt;a href=&quot;https://twitter.com/jsrois/status/811341574885904384&quot;&gt;December 20, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Mega cursazo! Gracias &lt;a href=&quot;https://twitter.com/trikitrok&quot;&gt;@trikitrok&lt;/a&gt; &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;@luisrovirosa&lt;/a&gt;  y gracias &lt;a href=&quot;https://twitter.com/Gradiant&quot;&gt;@Gradiant&lt;/a&gt; por traerlos! A ver si vuelven 😉&lt;a href=&quot;https://t.co/pMuI7aZl2E&quot;&gt;https://t.co/pMuI7aZl2E&lt;/a&gt;&lt;/p&gt;&amp;mdash; Fernando Vilas (@fer_vilas) &lt;a href=&quot;https://twitter.com/fer_vilas/status/811281824097927168&quot;&gt;December 20, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;Como siempre acabamos cansadísimos pero muy contentos porque creo que conseguimos nuestro objetivo de iniciar al grupo en testing y TDD, y de ilusionarlos para empezar a aventurarse en una forma de trabajo diferente.&lt;/p&gt;

&lt;p&gt;Antes de terminar quería darle las gracias especialmente a &lt;a href=&quot;https://twitter.com/jsrois&quot;&gt;Javi Sánchez Rois&lt;/a&gt; y a &lt;a href=&quot;https://twitter.com/fer_vilas&quot;&gt;Fernando Vilas&lt;/a&gt; por acogernos, llevarnos a sitios ricos para comer y presentarnos al &lt;a href=&quot;https://twitter.com/dinosetovigo?lang=es&quot;&gt;Dinoseto&lt;/a&gt; 😉.&lt;/p&gt;
</description>
          <pubDate>2016-12-27T07:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/12/estuvimos-en-gradiant</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/12/estuvimos-en-gradiant</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre connascence en SCBCN 2016</title>
          <description>&lt;p&gt;El pasado Octubre &lt;a href=&quot;https://twitter.com/fran_reyes&quot;&gt;Fran&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/AlfredoCasado&quot;&gt;yo&lt;/a&gt; preparamos una charla para la &lt;a href=&quot;/2016/11/estuvimos-en-la-software-craftsmanship-bcn-2016&quot;&gt;Software Craftsmanship Barcelona 2016&lt;/a&gt; explicando el concepto de &lt;a href=&quot;https://en.wikipedia.org/wiki/Connascence_(computer_programming)&quot;&gt;connascence&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Podemos entender &lt;strong&gt;connascence&lt;/strong&gt; como la relación entre N componentes de software que implica que cuando se cambia uno de esos N componentes los N-1 componentes restantes se tienen que cambiar para mantener la integridad del sistema completo. En otras palabras, lo que nos ofrece &lt;strong&gt;connascence&lt;/strong&gt; es una forma mucho más rica para referirnos y expresar diferentes tipos de acoplamiento. Se podría decir que del mismo modo que los patrones de diseño nos ofrecen un vocabulario para hablar de diseño orientado a objetos, &lt;strong&gt;connascence&lt;/strong&gt; nos ofrece un vocabulario para hablar de acoplamiento.&lt;/p&gt;

&lt;p&gt;A partir de esta &lt;a href=&quot;https://vimeo.com/10837903&quot;&gt;charla de Jim Weirich&lt;/a&gt; nos empezamos a interesar por el tema y decidimos preparar una pequeña charla para profundizar sobre el tema, presentarla a la comunidad y debatir un poco sobre el concepto.&lt;/p&gt;

&lt;p&gt;Los amigos de Software Craftsmanship Barcelona acaban de publicar el video de la charla, aunque como Fran no pudo asistir van a tener que aguantarme a mi sólo todo el video, je, je:&lt;/p&gt;

&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;bIr5fPom7B4&quot;&gt;
    &lt;div data-id=&quot;bIr5fPom7B4&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/bIr5fPom7B4/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Y aquí tenéis &lt;a href=&quot;http://slides.com/alfredocasado-1/deck#/&quot;&gt;las slides que utilizamos en la charla&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Espero que les resulte tan interesante como a nosotros, todos los comentarios son bienvenidos!&lt;/p&gt;

&lt;div class=&quot;foot-note&quot;&gt;
  Usamos la imagen de tipos de connascence de &lt;a href=&quot;https://silkandspinach.net/&quot;&gt;Kevin Rutherford&lt;/a&gt;.
&lt;/div&gt;
</description>
          <pubDate>2016-12-22T06:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/12/charla-sobre-connascence-en-scbcn16</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/12/charla-sobre-connascence-en-scbcn16</guid>
        </item>
      
    
      
        <item>
          <title>Charla sobre destructuring en Clojure</title>
          <description>&lt;p&gt;Recientemente 
&lt;a href=&quot;http://garajeando.blogspot.com.es/2016/11/codesai.html&quot;&gt;me uní a Codesai&lt;/a&gt;
, y como muchos saben por mi &lt;a href=&quot;http://garajeando.blogspot.com.es/&quot;&gt;blog personal&lt;/a&gt; estoy encantado con Clojure.&lt;/p&gt;

&lt;p&gt;Como algunos miembros de Codesai querían aprender Clojure/ClojureScript, decidimos empezar un pequeño grupo de estudio en remoto (Codesai es un equipo distribuido) contando conmigo como mentor.&lt;/p&gt;

&lt;p&gt;Para ello creamos un slack, &lt;b&gt;clojuresai&lt;/b&gt;, donde voy posteando lecturas (estamos leyendo 
&lt;a href=&quot;http://www.braveclojure.com/clojure-for-the-brave-and-true/&quot;&gt;Clojure for the Brave and True&lt;/a&gt;) y ejercicios (estamos haciendo una selección de los ejercicios de 
&lt;a href=&quot;http://www.4clojure.com/&quot;&gt;4Clojure&lt;/a&gt;) cada semana. Además hay canales donde pueden preguntar dudas o hacer comentarios tanto sobre las lecturas como los ejercicios, y compartir cualquier cosa que encuentren interesante.&lt;/p&gt;

&lt;p&gt;A los pocos días de crear el grupo de estudio, algunos compañeros del meetup &lt;a href=&quot;https://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Developers Barcelona&lt;/a&gt; que están empezando con Clojure, se nos unieron también.&lt;/p&gt;

&lt;p&gt;De vez en cuando, hacemos charlas introductorias en remoto usando Google Hangouts para profundizar en algunos temas que hemos leido hace poco en el libro.&lt;/p&gt;

&lt;p&gt;Hasta ahora hemos hecho dos charlas. La primera fue sobre las colecciones de Clojure, pero desgraciadamente no la pudimos grabar. De todas formas, les comparto &lt;a href=&quot;https://gist.github.com/trikitrok/57d5a6a221682f1c3b4c&quot;&gt;aquí los ejemplos que usamos en esa charla&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hace un par de semanas hicimos nuestra segunda charla remota. Esta vez profundizamos en el destructuring, y sí que la pudimos grabar, lo cual vino muy bien porque algunos miembros del grupo de estudio no pudieron conectarse.&lt;/p&gt;

&lt;p&gt;Esta es la grabación de la charla:&lt;/p&gt;
&lt;div class=&quot;video&quot;&gt;
  &lt;div class=&quot;youtube-player&quot; data-id=&quot;qMcjufX8czs&quot;&gt;
    &lt;div data-id=&quot;qMcjufX8czs&quot;&gt;
      &lt;img src=&quot;https://i.ytimg.com/vi/qMcjufX8czs/hqdefault.jpg&quot; alt=&quot;Video thumbnail&quot; /&gt;
      &lt;div class=&quot;play&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  
  
&lt;/div&gt;

&lt;p&gt;Además pueden encontrar &lt;a href=&quot;https://gist.github.com/trikitrok/e24b0a8ecacf8c1ae726#file-destructuring-talk-clj&quot;&gt;aquí todos los ejemplos que usé para explicar el destructuring&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Me gustaría darle las gracias de manera especial a &lt;a href=&quot;https://twitter.com/rojo_angel&quot;&gt;Ángel&lt;/a&gt; y a &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento&lt;/a&gt; Barcelona por dejarme hacer la charla desde su oficina (su conexión a internet es muchísimo mejor que la mia).&lt;/p&gt;

&lt;p&gt;Antes de terminar quiero mencionar que &lt;a href=&quot;https://twitter.com/mgdelacroix&quot;&gt;Miguel de la Cruz&lt;/a&gt;, también se ha unido como mentor a nuestro grupo de estudio (¡muchísimas gracias Miguel!). Sabe mucho Clojure y ayudará resolviendo dudas y preparando otras charlas que esperamos compartir pronto.&lt;/p&gt;

&lt;p&gt;Espero que les sea útil.&lt;/p&gt;
</description>
          <pubDate>2016-12-15T10:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/12/charla-clojure-destructuring</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/12/charla-clojure-destructuring</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Ve Interactive</title>
          <description>&lt;p&gt;Hace unas semanas &lt;a href=&quot;https://twitter.com/luisrovirosa&quot;&gt;Luis Rovirosa&lt;/a&gt; y yo impartimos una formación de TDD en las oficinas de &lt;a href=&quot;https://twitter.com/veinteractivebi&quot;&gt;Ve Interactive en Bilbao&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Luis lleva bastante tiempo impartiendo el &lt;a href=&quot;http://www.codesai.com/curso-de-tdd/&quot;&gt;curso de TDD de Codesai&lt;/a&gt;, tanto en solitario como junto con &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;Carlos Blé&lt;/a&gt;, pero para mi era la privera vez. Me gustó mucho la estructura y el ritmo que le da Luis al curso.&lt;/p&gt;

&lt;p&gt;Se trata un curso muy intenso y eminentemente práctico que dura dos días, cada uno de los cuales se divide en cuatro bloques de dos horas. Al comienzo de cada bloque presentamos una serie de conceptos teóricos, que comentamos y debatimos con el grupo, y rápidamente pasamos a ponerlos en práctica mediante una serie de katas de complejidad y dificultad creciente, en las que acompañamos continuamente a las parejas dándoles feedback y contestando sus dudas, para que los conceptos acaben de ser asimilados.&lt;/p&gt;

&lt;p&gt;Fue todo un placer trabajar con los 14 desarrolladores que asistieron al curso. Era un grupo con una actitud genial y con un nivel muy bueno. A pesar de lo intenso del curso, trabajaron con mucho entusiasmo cada uno de los ejercicios y se produjeron debates muy interesantes y constructivos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/curso_tdd_veInteractive.jpg&quot; alt=&quot;asistentes al curso de TDD en veInteractive&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Nos fuimos de Bilbao exhaustos, pero muy contentos, tanto por las personas que conocimos como por el feedback que recibimos. Personalmente, me encanto trabajar con Luis y aprendí muchísimo de él.&lt;/p&gt;
</description>
          <pubDate>2016-12-09T09:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/12/estuvimos-en-veinteractive</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/12/estuvimos-en-veinteractive</guid>
        </item>
      
    
      
        <item>
          <title>Inolvidable CAS2016 Vitoria-Gasteiz</title>
          <description>&lt;p&gt;
  Nada más terminar CAS2015 teníamos muy claro que queríamos estar en CAS2016, entre otras cosas por el cariño que tenemos a los organizadores, nuestros buenos amigos del norte, que yo considero referentes en muchos aspectos. Teníamos las expectativas muy altas con respecto a la organización y no solo las han cumplido sino que las han superado con creces.
&lt;/p&gt;

&lt;p&gt;
  Nos ofrecimos a patrocinar desde que se abrió el plazo porque sabíamos que se petaría de organizaciones queriendo ser parte de los patrocinadores y así fué. Por cierto, se nos olvidó encargar nuestras pegatinas molonas y no llegamos a poner una en cada bolsa. Si alguien no consiguió pegatina, nos puede escribir y se la enviamos por correo. Aprovecho para agradecer a Luz de &lt;a href=&quot;https://www.ambidiextro.com/&quot;&gt;Ambidiextro&lt;/a&gt; que se puso a trabajar a toda máquina en las pegatinas habíendolas pedido con solo 4 días de antelación y además se desplazó a traerlas en mano a la oficina.
&lt;/p&gt;

&lt;p&gt;
  Tuve la suerte de que mi propuesta de charla fue aceptada y encima en la agenda estaba el primer día, al principio del evento. Mi hora preferida. Por un lado la noche anterior me dió mucha pena no ir a la cena con ponentes y organizadores pero la prioridad era descansar para dar mi mejor versión durante mi sesión. Por otro lado, ya el resto del evento me pude centrar en absorber conocimiento y hablar con todo el mundo. En los eventos hablo hasta con las columnas.
&lt;/p&gt;


&lt;hr&gt;
&lt;div class=&quot;row&quot;&gt;
	&lt;div class=&quot;col-md-12&quot;&gt;
		&lt;div class=&quot;slideshare-embed&quot;&gt;
			&lt;iframe src=&quot;https://www.slideshare.net/slideshow/embed_code/key/4IHtiPuupOukIP&quot; frameborder=&quot;0&quot; allowfullscreen scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;

&lt;p&gt;
  Me encontré muy cómodo en el escenario y pude contar lo que quería. Después recibí feedback muy interesante que me llevó a cambiar mis slides antes de colgarlas y a abrir la mente. Tengo comprobado que las charlas me salen como yo quiero cuando las trabajo mucho. Hago un trabajo profundo de divergencia y convergencia para ordenar mis ideas, filtrar los contenidos, escribir un guión, montar las slides... en el escenario parece natural cuando en realidad es bastante artificial, tengo practicamente todas las frases memorizadas de haber hecho la charla como 10 veces en casa. Las primeras veces voy leyendo el guión y midiendo el tiempo que tardo y observando si me siento cómodo o incómodo verbalizando en voz alta el guión, de tal manera que lo voy ajustando a lo que me resulta mas natural decir en voz alta. Decido qué pequeñas bromas quiero hacer y cuales no. El resultado parece natural y fluido, como improvisado, pero mi capacidad de improvisar es limitada y de un tiempo a esta parte no me la juego. Pongo el foco en transmitir el mensaje con eficacia, buscar la forma de causar impacto. En otros eventos como open spaces si me gusta más improvisar. En las últimas charlas que he hecho en inglés últimamente, me ha faltado ensayarlas más veces.
  Es por este motivo que antes no le veía sentido a repetir la misma charla en diferentes conferencias y ahora sí, cuando la audiencia es diferente y el asunto me parece relevante.
&lt;/p&gt;

&lt;p&gt;
  Muchas gracias a todos por venir, especialmente a los que participaron en el turno de preguntas o me dieron feedback directo. No me había dado cuenta que cuando hablé por encima de &lt;a href=&quot;https://en.wikipedia.org/wiki/Design_thinking&quot;&gt;Design Thinking&lt;/a&gt; pudo haber sonado algo despectivo o infravalorado cuando en realidad pienso todo lo contrario, me parece super interesante.
&lt;/p&gt;

&lt;p&gt;
  En el taller de Silvia Calvet y Gastón Valle, me dí cuenta que compartimos muchas cosas y me reforzaron la idea de probar la técnica &lt;a href=&quot;http://www.gv.com/sprint/&quot;&gt;Design Sprint&lt;/a&gt; que la conocía gracias a la sesión de Aritz Suescun en AOS2016. El taller me gustó mucho pese a llegar tarde. Tuve un buen intercambio  de información con Silvia y Gastón. Les estoy agradecidos a los tres.
&lt;/p&gt;

&lt;p&gt;
  Creo que la charla se grabó, si se publica actualizaré este post con el vídeo.
&lt;/p&gt;

&lt;p&gt;
  La agenda de esta CAS me resultaba tan interesante que en todos los slots quería ir a tres cosas a la vez. Felicidades a los chairs, a mí la agenda me ha parecido brutal. A menudo eran amigos míos a los que quería ver para poderles dar feedback y hacer un poquito de cobertura en twitter pero era imposible. Algunas sesiones directamente me las perdí porque estaba inmerso en alguna excitante conversación de pasillo y café. De hecho al taller de DS llegué tarde porque ví a Bob Marshall muy solo y aproveché a charlar un ratito con él. Estuvimos hablando de Comunicación no violenta (CNV), de cambio organizacional y hasta del Brexit...
&lt;/p&gt;

&lt;p&gt;
  Me pasó lo mismo con Chris Matts que nos pusimos de charla y al final a penas participé en el taller de Event Storming de Vicenç. Conocía a Chris de coincidir en networking en varias conferencias en el extranjero y tenía ganas de verle porque es muy cercano y te cuenta lo último que tiene en mente a poco que le des pié. Tuvo el detallazo de regalarme una copia firmada de su libro Commitment :-D
&lt;/p&gt;

&lt;p&gt;
  Vengo siguiendo su corriente de pensamiento desde hace tiempo, junto a Dan North, con lo cual no me sorprende que una de mis slides tuviese un gran martillo y en la suya tambien y ambos dijésemos esto de que cuando uno tiene un martillo todo parecen clavos. Interpreté algunas coincidencias más con mensajes de Chris y Bob como lo de hablar de necesidades. No es casualidad.
&lt;/p&gt;

&lt;p&gt;
  Me gustó verles en el evento, agradezco el esfuerzo de la organización por traerles. Sin embargo me sentí algo impotente cuando veía a Bob muy sólo durante la conferencia, parece que quería hablar con la gente pero no se producía acercamiento. La noche del jueves no le ví en la fiesta. Este tema de integrar a los que vienen de fuera, pienso que lo seguimos teniendo pendiente de mejora.
&lt;/p&gt;

&lt;p&gt;
  La CAS de Vitoria ha sido un subión constante, mucho cariño y respeto en el ambiente. Veo una evolución en nuestra comunidad que es emocionante. Estoy tremendamente agradecido a la organización por hacerlo posible. El lugar era ideal.
  &lt;br/&gt;
  La humildad de los organizadores, su valentia al presentar, el esfuerzo porque todos estuviesen contentos durante la jornada y tambien por la noche, estar todo el tiempo pendientes cuidando de nosotros para que los detalles pequeños como guardar el abrigo y la maleta, o tomar un cafe y una fruta entre horas... es impresionante. Mil gracias y enhorabuena de corazón. Y en la organizacion estoy por supuesto incluyendo a los track chairs.
&lt;/p&gt;

&lt;p&gt;
  Aprovecho para dar las gracias a todas las personas con las que pude compartir un ratito. Sin ningún tipo de orden:
&lt;/p&gt;

&lt;p&gt;
  Luis Artola, Guillermo Galmazor, David Gonzalez, Alvaro Amor, Alberto Paz, Joaquin Engelmo, David Fernandez, Marta San Martín, David Jímenez, Carlos Valle, Unai Roldán, Gerardo Ponte, Fernando y Arcangel, Primi Cachero, Beatriz Martín, Maica Trinidad, Raquel Lainde, Jose E. Rodriguez Huertas, Roberto Canales, Vicenç García-Altes, Amalia Hernández, Leo Márquez, David Parra, Oriol del Barrio, Oriol Soriano, Roberto Matas, Rafa, Xavier Albaladejo, Pablo Domingo, Silvia Sistaré, Javier Prieto, Patricia Egea, Aritz Suescun, Joserra Díaz, Jorge Uriarte, Rubén Bernardez, Rubén Eguiluz, APA, Gorka Moreno, Pablo Albizu, Iker Mariñelarena, Néstor Salceda, Javier Rubio, Xabi Sáez, Patxi Esteban, Diego Rojas, Andrea Vega, Fernando Palomo.
&lt;/p&gt;

&lt;p&gt;
  Agradecimientos especiales a:
&lt;/p&gt;

&lt;p&gt;
  Mi compañero Antonio de la Torre por su valentía presentando un tema complejo. Por compartir habitación y cuidar de nosotros. Por hacer una buena cobertura en twitter a Codesai.
&lt;/p&gt;

&lt;p&gt;
  Modesto San Juan por encargarse de las pegatinas, ayudarnos a repartirlas y animar a Ronny a copresentar.
&lt;/p&gt;

&lt;p&gt;
  Edu Cabrera por transmitirme su visión y darme feedback. Edu enfocó mi mensaje desde el punto de vista de las personas y me animó a pensar en potenciar las virtudes y no solo a buscar problemas. Y que esta busqueda se haga conjuntamente con el equipo para que todo se sientan partícipes, co-descubriendo las virtudes y co-creando la solución. Esto apodera al equipo y cambia la cultura. Así no hay que vender nada a nadie. Hablamos de muchas cosas más, todas muy reveladoras. Como por ejemplo invitar a clientes a restrospectivas y demos internas.
&lt;/p&gt;

&lt;p&gt;
  Alberto Gomez por presentarnos a tanta gente interesante y lo estupendo que ha sido poder hablar en persona del proyecto en el que estamos trabajando juntos.
&lt;/p&gt;

&lt;p&gt;
  Edu Ferro por compartir sus slides conmigo.
&lt;/p&gt;

&lt;p&gt;
  Jose Manuel Beas por las fotos y conversaciones.
&lt;/p&gt;

&lt;p&gt;
  Isidro López por animarme a seguir compartiendo.
&lt;/p&gt;

&lt;p&gt;
  José Torres y Carlos Seisdedos por aquella conversación nocturna, alejados del ruido.
&lt;/p&gt;

&lt;p&gt;
  Oscar Prada y Antonio Lopez por compartir la forma en que están vitaminando a sus equipos.
&lt;/p&gt;

&lt;p&gt;
  Mis compañeros de AIDA Software por estar ahí siempre apoyando: Carlos Seisdedos, Jesús Quintana y Miguel A. Umpierrez
&lt;/p&gt;

&lt;p&gt;
  Ronny Ancorini por acompañarme a la sala para darme apoyo antes de arrancar mi charla.
&lt;/p&gt;

&lt;p&gt;
  Patxi, Alex Ballarin y Gerard Chiva por el viaje de Bilbao a Vitoria. También a Gerar y Tony Tassani por agradable cena.
&lt;/p&gt;

&lt;p&gt;
  Carlos Iglesias, Jordi Hernández y Lesmes López por el viaje de Vitoria a Bilbao. Me gustó mucho saber más de Runroom y sus valores.
&lt;/p&gt;

&lt;p&gt;
  A Dani Latorre por invitarme a un hangout para intercambiar impresiones para su charla y luego por hablar tan bien de nosotros en el escenario. La presentación de Dani me pareció valiente, sincera y muy divertida.
&lt;/p&gt;

&lt;p&gt;
  Carmen por su solidaridad conmigo en Barcelona, pasando miedo juntos con el taxista que conducía como un formula 1 por Barcelona.
&lt;/p&gt;

&lt;p&gt;
  Gracias a todos los que me pusieron pegatinas con Kudos (yo perdí los míos y no le puse a nadie). Y a todos los que subieron a twitter fotos de nuestras sesiones.
&lt;/p&gt;

&lt;p&gt;
  Me quede con las ganas de hablar con mas amigos, pero no dio tiempo para mas. ¡Nos vemos en CAS2017, donde quiera que sea!
&lt;/p&gt;
</description>
          <pubDate>2016-12-08T17:25:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/12/inolvidable-cas2016-vitoria-gasteiz</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/12/inolvidable-cas2016-vitoria-gasteiz</guid>
        </item>
      
    
      
        <item>
          <title>Así viví Codemotion 2016</title>
          <description>&lt;img src=&quot;/assets/IMG_0377.jpg&quot; alt=&quot;img_0377&quot;&gt;

&lt;p&gt;
  Para mí el primer Codemotion y ha sido impactante, un eventazo de lo mejor. No me explico cómo es que no había estado antes.
&lt;/p&gt;

&lt;p&gt;
  Me lo he pasado bomba, he aprendido mucho, me he encontrado con muchísimos amigos, desvirtualizado a mucha gente y me he sentido en un ambiente acogedor y colaborativo, cosa que no es fácil teniendo en cuenta que hemos estado ¿2600 personas? Cuando estuve en la inspiradora ponencia de Jorge Barroso en el Track1, puede contar sentadas unas 400 personas y habíamos decenas de personas de pie. Por cierto que siempre que veo a Jorge aprendo, tanto de valores y cultura como de exponer en público. Me llevo muchas cosas para la saca. Recomiendo verla tranquilamente en casa.
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;La organización ha hecho un trabajo brillante y los voluntarios han sido encantadores, muy atentos en todo momento.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Hace poquito escribía un post sobre las conferencias y la comida. Curiosamente en Codemotion el tema de la comida se resolvió justo como más me gusta. Había opción vegetariana, vegana y sin gluten y todo estaba en el mismo sitio, con lo cual comer no era un problema. El segundo día llegué tarde y se había agotado lo vegano. Es una buena señal, un dato que puede usarse para que en futuras ediciones vaya aumentando el número de unidades veganas ya que gente no vegana también lo quería comer. Estaba muy rico. Eché de menos que la cafetería no estuviese abierta el sábado. El viernes tuve muy buenas conversaciones en la cafetería, donde además el café y las tostadas eran cojonudas. Poder comer al aire libre fué un plus los dos días.
&lt;/p&gt;

&lt;p&gt;
  La cena de ponentes del jueves fue en un lugar ideal para el networking y pasamos unas horas estupendas. Pena que lo único vegano que hubo fue la fruta del postre pero tampoco iba hambriento. Todo un detallazo lo de montar evento de networking para ponentes para ir calentando. Las salas eran ideales para este formato de conferencias y las indicaciones para llegar a las mismas también.
&lt;/p&gt;

&lt;p&gt;
  Me ha parecido que el comportamiento de la gente ha sido muy cívico.
  &lt;br /&gt;
  Ir el viernes en bus desde Plaza España funcionó estupendamente y para volver ese día también muy bien.
  &lt;br /&gt;
  El sabado eché de menos no haberme organizado para compartir taxi al aeropuerto porque había mucha gente en al misma situación y al final se pidieron taxis de más y acabé yendo solo.
  &lt;br /&gt;
  El viernes el registro fue rapidísimo. La conexión a internet me funcionó mucho mejor de lo que esperaba habiendo tantísimos dispositivos conectados.
  &lt;br /&gt;
  Todas las sesiones a las que fuí me aportaron valor, la gente se había preparado muy bien el material de ponencias y talleres. Como siempre no se puede ir a todo pero tener muchas grabadas resuelve parte del problema. Estoy deseando verlas en casa. 
&lt;/p&gt;

&lt;img src=&quot;/assets/IMG_0357.jpg&quot; alt=&quot;IMG_0357&quot;/&gt;

&lt;p&gt;
  He sido ponente, creo que un poco de rebote porque inicialmente no entró en la agenda mi propuesta pero unas semanas antes del evento me avisaron de que había un hueco y entraba. Quiero dar las gracias a la comunidad ágil por votar la sesión y a la organización por la oportunidad.
&lt;/p&gt;

&lt;img src=&quot;/assets/IMG_0358.jpg&quot;  alt=&quot;IMG_0358&quot;/&gt;

&lt;p&gt;
  Muchas gracias a los asistentes. La había trabajado mucho las semanas anteriores, la había rodado el día anterior en IronHack y tuve suerte de estar fresco ese día y contar las cosas tal como me has había preparado. Así que muy contento.
&lt;/p&gt;

&lt;p&gt;
  Me dirigí a la sala casi 15 minutos antes de empezar porque no sabía ni donde estaba ubicada. Al bajar a la planta, enseguida me encontré una cola de gente enorme en el pasillo. Un pasillo muy largo que debe tener más de 50 metros. No sabía de qué era pero conforme caminaba buscando la sala me daba cuenta que era para ir a esta sesión. 
&lt;/p&gt;


&lt;img src=&quot;/assets/IMG_0359-1.jpg&quot; alt=&quot;img_0359&quot; /&gt;

&lt;p&gt;
  La cola era impresionante, nunca había visto una cosa así. Estuvo a reventar y se quedó gente fuera.
  &lt;br /&gt;
  Aquí se ven fotos que hice unos minutos antes de la charla, donde ahora que las veo me doy cuenta que hay como 5 personas saludando a la cámara, haciendo gesto de apoyo. Cuando las hacía no me dí cuenta. Daba gusto ver tantas caras conocidas entre los asistentes.
&lt;/p&gt;

&lt;img src=&quot;/assets/IMG_0360.jpg&quot; alt=&quot;img_0360&quot; /&gt;

&lt;p&gt;
  Puesto para mí la parte de interacción con los asistentes es de las más enriquecedoras, he aprendido que para otra ocasión es mejor decirselo así a la gente antes de cerrar la charla, para que no salgan corriendo despues de mi última slide, ya que había reservado tiempo extra precisamente para tener tiempo para preguntas y respuestas tranquilamente. Pedí a la gente que por favor no hicieran ruido al salir y pudimos tener esa sesión de preguntas que me permitió contar más cosas que tenía preparadas. En la ronda de preguntas es donde sale a relucir parte del material que genero preparando la charla, pero que descarto de las slides para asegurarme que hay interacción y así va con más contexto.
  &lt;br /&gt;
  Gracias a todos los que expresaron feedback e incluso fotos y palabras de apoyo en twitter y en la &lt;a href=&quot;https://2016.codemotion.es/agenda.html#5732408326356992/86444010&quot; &gt;agenda del evento&lt;/a&gt;:&lt;/p&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;section class=&quot;twitter-embeds&quot;&gt;
  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Ha estado genial la charla de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt;, enhorabuena. &lt;a href=&quot;https://t.co/B8wcaaYwBx&quot;&gt;pic.twitter.com/B8wcaaYwBx&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jorge Sánchez (@xurxodev) &lt;a href=&quot;https://twitter.com/xurxodev/status/799643755628392448&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Me ha gustado mucho la charla de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; en &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt;. Interesante y llena de sentido común. &lt;a href=&quot;https://t.co/noSMAKDvdV&quot;&gt;pic.twitter.com/noSMAKDvdV&lt;/a&gt;&lt;/p&gt;&amp;mdash; Vandergil (@LaVandergil) &lt;a href=&quot;https://twitter.com/LaVandergil/status/799636774339284992&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Fichad eso. Y preguntad directamente a &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; por cómo hay que conocer el contexto... vaya pedazo de charla. 😍😍 &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; &lt;a href=&quot;https://t.co/CFGixVXQnt&quot;&gt;pic.twitter.com/CFGixVXQnt&lt;/a&gt;&lt;/p&gt;&amp;mdash; Salva (@salvadelapuente) &lt;a href=&quot;https://twitter.com/salvadelapuente/status/799632904443658240&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Hay dos cosas sagradas en el mundo del desarrollo:la religión y el rey.Aquí ambos, con una foto de Felipe al lado &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; &lt;a href=&quot;https://t.co/IJ9i3Y0ktt&quot;&gt;pic.twitter.com/IJ9i3Y0ktt&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jose Armesto (@fiunchinho) &lt;a href=&quot;https://twitter.com/fiunchinho/status/799630942201581571&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;&amp;quot;Hola, me llamo &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; y soy desarrollador&amp;quot;. Los más grandes no necesitan adornarse ni con corbatas ni con firmas de 10 palabras &lt;a href=&quot;https://t.co/nyfNOAZ3YU&quot;&gt;pic.twitter.com/nyfNOAZ3YU&lt;/a&gt;&lt;/p&gt;&amp;mdash; Iñaki Pérez (@ialbeniz) &lt;a href=&quot;https://twitter.com/ialbeniz/status/799643042248622080&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;¡Grande &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt;! ¡Me ha encantado la charla! Me llevo varias ideas para mejorar 🤓 &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; &lt;a href=&quot;https://t.co/0ZCRIitaYR&quot;&gt;pic.twitter.com/0ZCRIitaYR&lt;/a&gt;&lt;/p&gt;&amp;mdash; Juan Lladó (@jllado) &lt;a href=&quot;https://twitter.com/jllado/status/799643862566404096&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Gran charla de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; hoy en &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; !! Me llevo varias ideas que pondré en práctica!!&lt;/p&gt;&amp;mdash; Rubén Sans Mudoy (@rbn_sans) &lt;a href=&quot;https://twitter.com/rbn_sans/status/799645458369015808&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-cards=&quot;hidden&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;It&amp;#39;s incredible what I can bear to listen to &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; Great! As usual! &lt;a href=&quot;https://t.co/Ye7FZ808r9&quot;&gt;pic.twitter.com/Ye7FZ808r9&lt;/a&gt;&lt;/p&gt;&amp;mdash; Raquel (@bberrycarmen) &lt;a href=&quot;https://twitter.com/bberrycarmen/status/799642939345408000&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Gran charla de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt;  con lleno absoluto!! &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt;&lt;/p&gt;&amp;mdash; Sergio (@s_barri) &lt;a href=&quot;https://twitter.com/s_barri/status/799640722919985152&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Si hubiera grabado el volumen de los aplausos os haríais una idea de lo wenisma que ha sido la charla de &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt;&lt;/p&gt;&amp;mdash; Salva (@salvadelapuente) &lt;a href=&quot;https://twitter.com/salvadelapuente/status/799640279779155969&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-offset-1 col-md-5 col-sm-12&quot;&gt;
      &lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;es&quot; dir=&quot;ltr&quot;&gt;Muy muy interesante la charla de Carlos Ble &lt;a href=&quot;https://twitter.com/carlosble&quot;&gt;@carlosble&lt;/a&gt; en &lt;a href=&quot;https://twitter.com/hashtag/Codemotion2016?src=hash&quot;&gt;#Codemotion2016&lt;/a&gt; &amp;quot;deja una solución abierta&amp;quot;&lt;/p&gt;&amp;mdash; karolrodtor (@karolrodtor) &lt;a href=&quot;https://twitter.com/karolrodtor/status/799636550866898944&quot;&gt;November 18, 2016&lt;/a&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-md-5 col-sm-12&quot;&gt;

    &lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;
  La charla también la voy a hacer en CAS2016 en Vitoria-Gasteiz pero desconozco si allí se grabará.
&lt;/p&gt;

&lt;p&gt;
  Uno de los puntos fuertes de los eventos es encontrarnos los compañeros de la comunidad Codesai. La comunidad es el equipo de Codesai más los amigos cercanos como Modesto y Laura. Modesto sigue estando en el canal de slack donde compartimos conocimiento y experiencias. Un lujo poder estar un rato con Alfredo, Antonio, Laura y Modesto. La ponencia de Alfredo y Laura me ha encantado, recomiendo estudiarla en casa con tranquilidad porque está repleta de experiencia destilada en materia de tests automáticos. Enhorabuena!  
&lt;/p&gt;

&lt;p&gt;
  En cuanto a conocimiento técnico me encantado de haber comprendido lo que es una mónada gracias a la ponencia de Juan Manuel Serrano (muy buena para verla en vídeo). Así con un buen ejemplo da gusto. Además la puesta en escena fue muy amena.
  &lt;br /&gt;
  Conocí Perceval de la mano de Alvaro del Castillo, herramienta muy interesante para proyectos que tenemos en mente. Nos confirmó que Kibana es una excelente herramienta.
  &lt;br /&gt;
  Por otro lado en el taller de Polymer de Jorge del Casar descubrí muchas cosas que no conocía, me quedé con ganas de más.
  &lt;br /&gt;
  La charla de Micael Gallego ha reforzado lo que ya Modesto venía sugiriendo de usar TypeScript y ha llegado el momento de probarlo. Usar TypeScript en lugar de ES6 o ES7 en algunos proyectos. De una manera bastante funcional, sin clases, similar a como usamos ES6 pero con la posibilidad de tipar cuando lo veamos adecuado. En definitiva usar la herramienta cuando aporta. Una charla muy divertida y esclarecedora.
  &lt;br /&gt;
  En la cafetería y pasillos pude aprender mucho con Salva de la Puente y con Israel Gutierrez sobre lenguajes, linters e incluso de hablar en público.
  &lt;br /&gt;
  Las charlas breves de Roberto Canales y Jose Luis Ugia me parecieron ambas muy buenas y me reforzaron ideas que van alineadas con sus mensajes.
  &lt;br /&gt;
  El sábado me perdí bastantes charlas entre que llegué tarde y me marche más temprano, las veré grabadas.
&lt;/p&gt;

&lt;p&gt;
  Conversaciones muy enriquecedoras con Ricardo Borillo, Jerónimo López, David Bonilla, Yeray Darias, Dani Latorre, Roberto Canales, Nacho Carretero, Félix López, Jose Armesto, Rubén Chavarría, Iván Abascal, Raúl Avila, Carlos Benitez, Joan León, Yamila Moreno, Daniel Piñeiro, Juan Lladó, David Fernández, Jorge del Casar, Joaquín Engelmo, Manuel Castro, Jorge Sánchez, Miguel Angel Bueno, Oscar Torres, Juan José Aguililla, Alvaro Amor, Alberto Paz, Alex Jover, Kiko Beats, Elena Torró, Javi Velasco, Javier Vélez, Jorge Senin, Rubén Díaz, Diego Rojas, Ezequiel, Isabel Rodriguez, Alba Roza, Jose Luis Ugia, Reinaldo Aguilera, Raquel Moreno, Eliezer López, Carlos Gámez, Dani Rey, David Gonzalo, Fran Raya, Daniel Cruz, Jose Turégano, Jaume Jornet, Pablo Domingo, Israel Alcázar, Raúl Navarrete, Alberto Lucas,  Alfredo de la Calle, por citar algunos nombres.
&lt;/p&gt;

&lt;p&gt;
  Me hubiera gustado poder hablar más tiempo para charlar con colegas y haberme encontrado en persona con otros sólo conozco virtualmente pero que al final ni nos llegamos a encontrar. No parecía que fuésemos tanta gente pero sí que lo éramos porque ni nos vimos. 
&lt;/p&gt;

&lt;p&gt;
  ¡Nos vemos en el próximo Codemotion!
&lt;/p&gt;
</description>
          <pubDate>2016-11-19T18:24:43+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/11/asi-vivi-codemotion2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/11/asi-vivi-codemotion2016</guid>
        </item>
      
    
      
        <item>
          <title>Using effects in re-frame</title>
          <description>&lt;p&gt;In &lt;strong&gt;&lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;&lt;/strong&gt;, we’d like to use &lt;strong&gt;pure event handlers&lt;/strong&gt; because they provide some important advantages, (mentioned in &lt;a href=&quot;/2016/10/using-coeffects-in-re-frame&quot;&gt;a previous post about &lt;strong&gt;coeffects&lt;/strong&gt; in &lt;strong&gt;re-frame&lt;/strong&gt;&lt;/a&gt;): &lt;strong&gt;local reasoning, easier testing, and events replay-ability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, as we said, to build a program that does anything useful, it’s inevitable to have some &lt;a href=&quot;http://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;&lt;strong&gt;side-effects&lt;/strong&gt; and/or &lt;strong&gt;side-causes&lt;/strong&gt;&lt;/a&gt;. So, there will be many cases in which &lt;strong&gt;event handlers&lt;/strong&gt; won’t be pure functions.&lt;/p&gt;

&lt;p&gt;We also saw how &lt;a href=&quot;/2016/10/using-coeffects-in-re-frame&quot;&gt;using &lt;strong&gt;coeffects&lt;/strong&gt; in re-frame&lt;/a&gt; allows to have &lt;strong&gt;pure event handlers in the presence of side-causes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, we’ll focus on &lt;strong&gt;side-effects&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If a function &lt;a href=&quot;https://en.wikipedia.org/wiki/Side_effect_(computer_science)&quot;&gt;modifies some state or has an observable interaction with calling functions or the outside world&lt;/a&gt;, it no longer behaves as a mathematical (pure) function, and then it is said that it does &lt;strong&gt;side-effects&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s see some examples of &lt;strong&gt;event handlers&lt;/strong&gt; that do &lt;strong&gt;side-effects&lt;/strong&gt; (from &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/09/kata-variation-on-cellular-automata.html&quot;&gt;a code animating the evolution of a cellular &lt;strong&gt;automaton&lt;/strong&gt;&lt;/a&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/343195d7137cdfb5f1e22bca7cac4a6e.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c85d132d79aec793196592ac48412406.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These &lt;strong&gt;event handlers&lt;/strong&gt;, registered using &lt;strong&gt;reg-event-db&lt;/strong&gt;, are &lt;strong&gt;impure&lt;/strong&gt; because they’re doing a &lt;strong&gt;side-effect&lt;/strong&gt; when they dispatch the &lt;strong&gt;:evolve event&lt;/strong&gt;. With this dispatch, they are performing &lt;a href=&quot;https://xivilization.net/~marek/blog/2015/02/06/avoiding-action-at-a-distance-is-the-fast-track-to-functional-programming/&quot;&gt;an action at a distance&lt;/a&gt;, which is in a way &lt;a href=&quot;http://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;a hidden output of the function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These &lt;strong&gt;impure event handlers&lt;/strong&gt; are hard to test. In order to test them, we’ll have to somehow &lt;strong&gt;spy&lt;/strong&gt; the calls to the function that is doing the &lt;strong&gt;side-effect&lt;/strong&gt; (the &lt;strong&gt;dispatch&lt;/strong&gt;). Like in the case of &lt;strong&gt;side-causes&lt;/strong&gt; &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/10/coeffects-in-re-frame.html&quot;&gt;from our previous post&lt;/a&gt;, there are many ways to do this in ClojureScript, (see &lt;a href=&quot;http://blog.josephwilk.net/clojure/isolating-external-dependencies-in-clojure.html&quot;&gt;Isolating external dependencies in Clojure&lt;/a&gt;), only that, in this case, the code required to test the &lt;strong&gt;impure handler&lt;/strong&gt; will be a bit more complex, because we need to keep track of every call made to the &lt;strong&gt;side-effecting function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this example, we chose to make explicit the dependency that the &lt;strong&gt;event handler&lt;/strong&gt; has on the &lt;strong&gt;side-effecting function&lt;/strong&gt;, and inject it into the &lt;strong&gt;event handler&lt;/strong&gt; which becomes a &lt;strong&gt;higher order function&lt;/strong&gt;. Actually, we injected a &lt;strong&gt;wrapper&lt;/strong&gt; of the &lt;strong&gt;side-effecting function&lt;/strong&gt; in order to create an easier interface.&lt;/p&gt;

&lt;p&gt;Notice how the &lt;strong&gt;event handlers&lt;/strong&gt;, &lt;strong&gt;evolve&lt;/strong&gt; and &lt;strong&gt;start-stop-evolution&lt;/strong&gt;, now receive as its first parameter the function that does the &lt;strong&gt;side-effect&lt;/strong&gt;, which are &lt;strong&gt;dispatch-later-fn&lt;/strong&gt; and &lt;strong&gt;dispatch&lt;/strong&gt;, respectively.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d800515bd08ae15e62d1ae2301e7a84a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;When the &lt;strong&gt;event handlers&lt;/strong&gt; are registered with the &lt;strong&gt;events&lt;/strong&gt; they handle, we &lt;strong&gt;&lt;a href=&quot;https://clojuredocs.org/clojure.core/partial&quot;&gt;partially apply&lt;/a&gt;&lt;/strong&gt; them, in order to pass them their corresponding &lt;strong&gt;side-effecting functions&lt;/strong&gt;, &lt;strong&gt;dispatch-later&lt;/strong&gt; for &lt;strong&gt;evolve&lt;/strong&gt; and &lt;strong&gt;dispatch&lt;/strong&gt; for &lt;strong&gt;start-stop-evolution&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/786c7b5b2fa0d6f3a0b36e746f49840f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These are &lt;strong&gt;the wrapping functions&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/6b4f0f22e98ca2f86715292d5af3e8ed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Now when we need to test the &lt;strong&gt;event handlers&lt;/strong&gt;, we use &lt;a href=&quot;https://clojuredocs.org/clojure.core/partial&quot;&gt;partial application&lt;/a&gt; again to inject the function that does the &lt;strong&gt;side-effect&lt;/strong&gt;, except that, in this case, the injected functions are &lt;strong&gt;test doubles&lt;/strong&gt;, concretely &lt;strong&gt;spies&lt;/strong&gt; which record the parameters used each time they are called:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1779b5af8ea5c49f640507c74024e277.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is very similar to what we had to do to test &lt;strong&gt;event handlers&lt;/strong&gt; with &lt;strong&gt;side-causes&lt;/strong&gt; in &lt;strong&gt;re-frame&lt;/strong&gt; before having &lt;strong&gt;effectful event handlers&lt;/strong&gt; (see &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/10/coeffects-in-re-frame.html&quot;&gt;previous post&lt;/a&gt;). However, the code for &lt;strong&gt;spies&lt;/strong&gt; is a bit more complex than the one for &lt;strong&gt;stubs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;strong&gt;test doubles&lt;/strong&gt; makes the &lt;strong&gt;event handler&lt;/strong&gt; testable again, but it’s still impure, so we have not only introduced more complexity to test it, but also, we have lost the two other advantages cited before: &lt;strong&gt;local reasoning&lt;/strong&gt; and &lt;strong&gt;events replay-ability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/CHANGES.md&quot;&gt;re-frame’s 0.8.0 (2016.08.19) release&lt;/a&gt;, this problem has been solved by introducing the concept of &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/EffectfulHandlers.md#effects-and-coeffects&quot;&gt;&lt;strong&gt;effects&lt;/strong&gt; and &lt;strong&gt;coeffects&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Whereas, in our &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/10/coeffects-in-re-frame.html&quot;&gt;previous post&lt;/a&gt;, we saw how &lt;strong&gt;coeffects&lt;/strong&gt; can be used to track what your program requires from the world (&lt;strong&gt;side-causes&lt;/strong&gt;), in this post, we’ll focus on how &lt;strong&gt;&lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Effects.md&quot;&gt;effects&lt;/a&gt;&lt;/strong&gt; can represent what your program does to the world (&lt;strong&gt;side-effects&lt;/strong&gt;). Using &lt;strong&gt;effects&lt;/strong&gt;, we’ll be able to write &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/EffectfulHandlers.md&quot;&gt;effectful event handlers&lt;/a&gt; that keep being pure functions.&lt;/p&gt;

&lt;p&gt;Let’s see how the previous &lt;strong&gt;event handlers&lt;/strong&gt; look when we use &lt;strong&gt;effects&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/17df67656aa8f5e9d8390df6bea8585d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how the &lt;strong&gt;event handlers&lt;/strong&gt; are not &lt;strong&gt;side-effecting&lt;/strong&gt; anymore. Instead, each of the &lt;strong&gt;event handlers&lt;/strong&gt; returns a &lt;strong&gt;map of effects&lt;/strong&gt; which contains several key-value pairs. Each of these key-value pairs declaratively describes an &lt;strong&gt;effect&lt;/strong&gt; using data. &lt;strong&gt;re-frame&lt;/strong&gt; will use that description to actually do the described &lt;strong&gt;effects&lt;/strong&gt;. The resulting &lt;strong&gt;event handlers&lt;/strong&gt; are pure functions which return descriptions of the &lt;strong&gt;side-effects&lt;/strong&gt; required.&lt;/p&gt;

&lt;p&gt;In this particular case, when the &lt;strong&gt;automaton&lt;/strong&gt; is evolving, the &lt;strong&gt;evolve event handler&lt;/strong&gt; is returning &lt;strong&gt;a map of effects&lt;/strong&gt; which contains two &lt;strong&gt;effects&lt;/strong&gt; represented as key/value pairs. The one with the &lt;strong&gt;:db key&lt;/strong&gt; describes the &lt;strong&gt;effect&lt;/strong&gt; of resetting the &lt;strong&gt;application state&lt;/strong&gt; to a new value. The other one, with the &lt;strong&gt;:dispatch-later key&lt;/strong&gt; describes the &lt;strong&gt;effect&lt;/strong&gt; of dispatching the &lt;strong&gt;:evolve event&lt;/strong&gt; after waiting 100 microseconds. On the other hand, when the &lt;strong&gt;automaton&lt;/strong&gt; is not evolving, the returned &lt;strong&gt;effect&lt;/strong&gt; describes that the &lt;strong&gt;application state&lt;/strong&gt; will be reset to its current value.&lt;/p&gt;

&lt;p&gt;Something similar happens with the &lt;strong&gt;start-stop-evolution event handler&lt;/strong&gt;. It returns &lt;strong&gt;a map of effects&lt;/strong&gt; also containing two &lt;strong&gt;effects&lt;/strong&gt;. The one with the &lt;strong&gt;:db key&lt;/strong&gt; describes the &lt;strong&gt;effect&lt;/strong&gt; of resetting the &lt;strong&gt;application state&lt;/strong&gt; to a new value, whereas the one with the &lt;strong&gt;:dispatch key&lt;/strong&gt; describes the &lt;strong&gt;effect&lt;/strong&gt; of immediately dispatching the &lt;strong&gt;:evolve event&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;effectful event handlers&lt;/strong&gt; are pure functions that accept two arguments, being the first one a &lt;strong&gt;map of coeffects&lt;/strong&gt;, and return, after doing some computation, an &lt;strong&gt;effects map&lt;/strong&gt; which is a description of all the &lt;strong&gt;side-effects&lt;/strong&gt; that need to be done by &lt;strong&gt;re-frame&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As we saw in &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/10/coeffects-in-re-frame.html&quot;&gt;the previous post about &lt;strong&gt;coeffectts&lt;/strong&gt;&lt;/a&gt;, re-frame’s &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/EffectfulHandlers.md&quot;&gt;effectful event handlers&lt;/a&gt; are registered using the &lt;strong&gt;reg-event-fx function&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7eca94fef23ad5178bde57a837ad978c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These are their tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8a723e933b2045e61939e96d5a1a0f1d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how by using &lt;strong&gt;effects&lt;/strong&gt; we don’t need to use &lt;strong&gt;tests doubles&lt;/strong&gt; anymore in order to test the &lt;strong&gt;event handlers&lt;/strong&gt;. These &lt;strong&gt;event handlers&lt;/strong&gt; are pure functions, so, besides &lt;strong&gt;easier testing&lt;/strong&gt;, we get back the advantages of &lt;strong&gt;local reasoning&lt;/strong&gt; and &lt;strong&gt;events replay-ability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:dispatch&lt;/strong&gt; and &lt;strong&gt;:dispatch-later&lt;/strong&gt; are &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Effects.md#builtin-effect-handlers&quot;&gt;builtin &lt;strong&gt;re-frame&lt;/strong&gt; &lt;strong&gt;effect handlers&lt;/strong&gt;&lt;/a&gt; already defined. It’s possible to create your own &lt;strong&gt;effect handlers&lt;/strong&gt;. We’ll explain how and show an example in a future post.&lt;/p&gt;
</description>
          <pubDate>2016-11-10T22:17:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/11/using-effects-in-re-frame</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/11/using-effects-in-re-frame</guid>
        </item>
      
    
      
        <item>
          <title>Segundo Flejesai de 2016</title>
          <description>&lt;figure&gt;
    &lt;img src=&quot;/assets/flejesai.jpg&quot; alt=&quot;team&quot; /&gt; 
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
  En Codesai somos un equipo distribuido. Actualmente trabajamos desde Gran Canaria, Tenerife, Barcelona, Madrid y Oviedo. Hacemos pair programming remoto, mob programming y videoconferencias semanales pero aún es muy importante reunirnos fisicamente un par de veces al año. La primera reunión fue en Las Palmas en Marzo de 2016. Nos sirvió para alinearnos, definir formas de trabajar, tomar decisiones y sobre todo compartir y hacer equipo. Esta segunda edición ha sido también en Las Palmas, los días 27 y 28 de octubre de 2016. El sitio de reunión ha sido espectacular, la sala de formación de la Galería de Arte de Manuel Ojeda, en Triana. Aprovechamos para agradecer a Manuel y Daniel Ojeda esta oportunidad, su amabilidad y su confianza.
&lt;/p&gt;

&lt;p&gt;
  Inicialmente esto se llamaba Codesai Summit pero como ahora somos muchos (un &lt;a href=&quot;http://www.academiacanarialengua.org/palabra/fleje/&quot;&gt;fleje&lt;/a&gt;), pues se nos ocurrió renombrarlo a Flejesai. Aunque fleje se usa más en la provincia de Las Palmas que en la de Santa Cruz, aceptamos la palabra como canario interinsular :-)
&lt;/p&gt;

&lt;p&gt;
  Fue genial contar con Antonio como facilitador durante los dos días de evento, para ponerle foco y sacar todos los temas que queríamos. El jueves facilitó la dinámica &lt;em&gt;Remember the Future&lt;/em&gt; donde imaginando que nos encontrábamos 12 meses en el futuro, hablábamos de esos últimos 12 meses como si fueran el pasado. Cada uno tuvo su turno de reflexión y luego de exposición. Alguno tuvo tiempo de escribir El Quijote en 5 minutos. Esto nos permitió a todos expresar metas y objetivos para el año. Ver en qué grado compartimos la visión y en qué grado es divergente. Posteriormente nos quedamos con los puntos más interesantes de todos los que salieron y nos pusimos a analizar juntos el por qué de esos objetivos. Este ejercicio nos sirvió para poner encima de la mesa nuestros valores y principios. Aunque sentimos que compartimos muchos valores y principios, hacerlo explícito nos ayudó a definir y aclarar ideas. 
&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/flejesai_reflexion.jpg&quot; alt=&quot;team_reflexion&quot; /&gt; 
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
  A continuación nuestros &lt;strong&gt;principios y valores&lt;/strong&gt; sin ningún tipo de orden de aparición:
  
  &lt;ul&gt;
    &lt;li&gt; Trabajamos con entrega, lo mejor que sabemos haberlo, aportando el máximo valor que somos capaces.&lt;/li&gt;
    &lt;li&gt; Contribuir a la evolución profesional de nuestro sector:
      &lt;ul&gt;
        &lt;li&gt; Hacer la vida más fácil a los usuarios.&lt;/li&gt;
        &lt;li&gt; Pensamos que los proyectos de desarrollo caóticos deberían ser una excepción y no la norma.&lt;/li&gt;
        &lt;li&gt; Eliminar la complejidad innecesaria.&lt;/li&gt;
        &lt;li&gt; Transmitir la pasión por lo que hacemos.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt; Mejorar y aprender constantemente.&lt;/li&gt;
    &lt;li&gt; La satisfacción del trabajo bien hecho.&lt;/li&gt;
    &lt;li&gt; Abrirnos a otros puntos de vista.&lt;/li&gt;
    &lt;li&gt; Alinear trabajo con propósito vital.&lt;/li&gt;
    &lt;li&gt; Pertenencia y reconocimiento.&lt;/li&gt;
    &lt;li&gt; Estabilidad y sostenibilidad del grupo en lugar de crecimiento.&lt;/li&gt;
    &lt;li&gt; Diversidad en el equipo.&lt;/li&gt;
    &lt;li&gt; Poder dar a los otros lo que nos hubiera gustado tener, por ejemplo una mejor educación técnica.&lt;/li&gt;
    &lt;li&gt; Poner la tecnología al servicio del bien común.&lt;/li&gt;
    &lt;li&gt; Evitar hacer daño, evitar que la tecnología se use contra las personas, los animales o el medio ambiente.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;En la sesión quedó claro que queremos desarrollar nuevos cursos de formación para armar un catálogo completo. Ya estamos trabajando en ello, recogiendo piedras de conocimiento para luego hacer las composiciones.
&lt;/p&gt;

&lt;p&gt;
  Todos pensamos que la web debe expresar mejor lo que hacemos y ser un lugar donde aglutinar nuestras publicaciones, queremos mejorarla. Es muy posible que dejemos wordpress por algo mas simple.
&lt;/p&gt;

&lt;p&gt;
  Hemos decidido dejar de utilizar las categorías de Craftsman, Journeyman, Apprentice, Junio y Senior para referirnos a lo que somos, tanto en la web como en las propuestas a clientes. Aunque a priori nos sentimos identificados con la metáfora de la artesanía del software, preferimos que la gente se haga una idea de nosotros a través de nuestros propios principios y valores.
&lt;/p&gt;

&lt;p&gt;
  En las propuestas a proyectos para clientes no enviaremos a individuos sino como mínimo parejas. Los costes serán por tanto por parejas o grupos más grandes pero no por persona. Realmente no necesitamos categorizar a nadie. Y queremos trabajar en pares o en grupo como lo venimos haciendo.
&lt;/p&gt;

&lt;p&gt;
  Queremos seguir teniendo presencia en eventos importantes de la comunidad, incluso dar el salto a eventos de fuera como &lt;a href=&quot;http://socratesuk.org/&quot;&gt;SocratesUK&lt;/a&gt;. Organizar una nueva edición de Socrates Canaries nos ilusiona.
&lt;/p&gt;

&lt;p&gt;
  Queremos balancear la carga entre trabajo de mentor y desarrollador. Nos gusta el desarrollo de producto y por eso buscamos disponer de más días donde somos desarrolladores y no mentores. Nos encanta hacer formación y mentoring pero no que sea lo mayoritario.
&lt;/p&gt;

&lt;p&gt;
  Queremos mejorar nuestro conocimiento en el paradigma funcional porque pensamos que puede mejorar la calidad de los productos que hacemos. Mantenernos al día con nuevas tecnologías, por ejemplo temas como React y Redux. Practicar más con arquitecturas como CQRS, Event Sourcing, modelo de actores...
&lt;/p&gt;

&lt;p&gt;
  Seguir dándole cuerpo a nuestro programa de aprendices y dar la bienvenida a nuevos aprendices, y si conseguimos que sean chicas mucho mejor.
  &lt;br /&gt;
No queremos crecer en número, crecer por crecer no es ningún objetivo. Pero si llega un momento en que nos sentimos cómodos y nos queremos comprometer a tener un nuevo compañero, pues nos gustaría que fuese una compañera.
&lt;/p&gt;

&lt;p&gt;
  Durante el evento aparte de pasar todo el día juntos, tuvimos largas cenas y sesiones nocturnas de charlas técnicas y no tan técnicas hasta la madrugada, donde pudimos compartir conocimiento, que es una de las cosas que más nos gusta del grupo. Echarnos unas risas juntos y algo de trolleo entre nosotros pero en plan sanote.
&lt;/p&gt;

&lt;p&gt;
  Hicimos retrospectiva, con un formato muy abierto donde todo el mundo podía expresar su punto de vista y nos ha salido una buena lista de acciones a realizar. Todo queda apuntado para revisarlo periódicamente y cuando nos juntemos en el próximo semestre mirar atrás y ver el avance.
&lt;/p&gt;

&lt;p&gt;
  Estos encuentros semestrales son muy motivadores. Ya tenemos ganas del próximo.
&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/flejesai_miguel_currando.jpg&quot; alt=&quot;team&quot; /&gt; 
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
</description>
          <pubDate>2016-11-04T18:19:11+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/11/segundo-flejesai-de-2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/11/segundo-flejesai-de-2016</guid>
        </item>
      
    
      
        <item>
          <title>Damos la bienvenida a Manuel Rivero</title>
          <description>&lt;p&gt;
  Menudo notición! &lt;a href=&quot;https://twitter.com/trikitrok&quot; &gt;Manuel Rivero&lt;/a&gt; se une al equipo Codesai! Fue algo antes de Software Craftsmanship Barcelona 2016 cuando Manuel me escribió expresando su intención de venir. La verdad es que no estabamos buscando crecer en número, pero a todo el equipo le encantó la idea. La mayoría le conocíamos y le tenemos como referente en el &lt;a href=&quot;https://plus.google.com/communities/114859785439968913587&quot; &gt; aprendizaje, en la comunidad&lt;/a&gt; y en muchos otros temas como la programación funcional. Manuel es fuente de conocimiento y no dudamos ni un segundo en aprovechar la oportunidad.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;http://garajeando.blogspot.com.es/2016/11/codesai.html&quot; &gt;Este post escrito en su blog&lt;/a&gt; habla acerca de su motivación para venir, en primera persona.
&lt;/p&gt;

&lt;img src=&quot;/assets/IMG_0196-1024x768.jpg&quot; alt=&quot;img_0196&quot; /&gt;

&lt;p&gt;
  Le conocí hace ya años en un curso abierto de TDD que impartí en Madrid. Es una de esas personas que se pagó el curso de su bolsillo, incluyendo viaje a otra ciudad, gastos de hotel y días de vacaciones. Este tipo de acciones dicen mucho de un profesional, no dejo de admirar a los que lo hacen y he aprendido mucho de todos ellos, además de que les sigo la pista todo lo que puedo. Desde entonces nos hemos encontrado muchas más veces en Barcelona, por ejemplo en una edición posterior del mismo curso donde me estuvo ayudando y en eventos de la comunidad. Es alucinante observar su evolución a lo largo de estos años. En todas las katas que he estado con Manuel, he aprendido cosas relevantes. Recuerdo, por ejemplo, el &lt;a href=&quot;http://wiki.c2.com/?DoubleDispatch&quot; &gt;double dispatch&lt;/a&gt; de Kent Beck que pese a haberlo leído no lo interioricé hasta que nos lo mostró con un ejemplo. Estamos muy ilusionados con todo lo que nos va a aportar, la mejor persona que puede entrar al equipo es aquella que tiene mucho que enseñarte. Desde ya, es nuestro Jedi del Clojure y del paradigma funcional. 
&lt;/p&gt;

&lt;p&gt;
  Ahora podemos decir que Codesai tiene presencia física en Barcelona, otro motivo más para visitar más a menudo esta maravillosa ciudad. 
&lt;/p&gt;

&lt;p&gt;
  Este cambio nos ha vuelto a motivar para retomar la preparación de nuevos cursos: Diseño Orientado a Objetos, Patrones, Refactoring y pronto seguro que también nos animamos con lo funcional. También está echando una mano desde ya con el desarrollo de productos para clientes, desarrollos que estamos llevando a cabo en estos momentos, participando en las sesiones de pair programming y mob programming.
&lt;/p&gt;

&lt;p&gt;
  Aunque lo anunciamos ahora, ya hace algunas semanas que estamos trabajando juntos. La semana pasada celebramos nuestro encuentro semestral, el Codesai Summit ahora renombrado como Flejesai (#flejesai16) y tuvimos la suerte de que aún estaba Modesto así que estabamos practicamente todos en el mismo lugar y lo pasamos genial. Pronto habrá un post sobre el Flejesai :-)
&lt;/p&gt;

&lt;p&gt;
  Aunque no estamos buscando crecer, es decir que no tenemos por objetivo ser más personas, sí tiene que ocurrir nos gustaría mucho que fuese una chica. Pensamos que la diversidad es muy importante. Ahí lo dejo ;-)
&lt;/p&gt;
</description>
          <pubDate>2016-11-02T22:17:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/11/damos-la-bienvenida-a-manuel-rivero</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/11/damos-la-bienvenida-a-manuel-rivero</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en la Software Craftsmanship BCN 2016</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/84024f3efe.jpg&quot; alt=&quot;84024f3efe&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;descripción-del-evento&quot;&gt;Descripción del evento&lt;/h3&gt;

&lt;p&gt;Este año varios miembros de Codesai estuvimos en la Software Craftsmanship de Barcelona. Todo un logro viendo que las primeras entradas fueron arrasadas, algo que habla muy bien de un evento que plantea dudas sobre si debería crecer más.&lt;/p&gt;

&lt;p&gt;Por fortuna, aunque las entradas se hayan vendido tan rápido, ha habido mucha cara nueva en el evento, lo que es realmente positivo viendo que el año pasado tardaron casi una semana en terminarse y que en un principio se pensaba que la mayoría de participantes habrían acudido en anteriores ediciones.&lt;/p&gt;

&lt;p&gt;A diferencia de la &lt;a href=&quot;/2016/06/estuvimos-en-pamplona-software-craftsmanship-2016&quot;&gt;Pamplona Software Craftsmanship&lt;/a&gt; que se realizó este mismo año el 17 y 18 de junio, el evento consta principalmente de charlas que se eligen después de que los ponentes las hayan presentado durante el C4P. Durante el último día del evento se dan unas cuantas horas para proponer sesiones para el Open Space. Contar con estos contrastes entre eventos dentro de la propia comunidad es algo muy valioso. Con cada evento al que asistimos nos percatamos que experiencias pasadas de otros eventos acaban reflejándose en mejoras para los siguientes.&lt;/p&gt;

&lt;p&gt;Los sponsors del evento han servido a los asistentes con una camiseta chulísima con la temática del evento y nos ofrecieron una bolsa genial con merchandising muy útil durante el evento que nos encantó a la mayoría de los asistentes. También mencionar sobre el lugar, un verdadero acierto, aunque a veces las salas se llenaban mucho y sentarse era una utopía, era muy cómodo estar en ellas y estaban muy bien ventiladas. Algo que se agradece de verdad.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/e05e30e614.jpg&quot; alt=&quot;e05e30e614&quot; /&gt;
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;gracias-a-la-organización&quot;&gt;Gracias a la organización!&lt;/h3&gt;

&lt;p&gt;Sin duda, un gran evento está respaldado por una gran organización. La Software Craftsmanship BCN 16 contó con una de las mejores ;). Había disponible un tablón de feedback desde la primera hora al que le echaban un ojo y procuraban asistir en lo posible. Durante la apertura se explicó el evento, las charlas fueron sobre ruedas, sin retrasos y durante el cierre se realizó una gran retrospectiva. Si es que no se encontraron problemas por ningún lado, muchas gracias y genial trabajo!&lt;/p&gt;

&lt;p&gt;Todas las charlas fueron grabadas con el apoyo de Codely.tv y los miembros de la organización, lo cual es un fantástico aporte, pues siempre hay horas en las que no sabes a qué charla ir :)&lt;/p&gt;

&lt;p&gt;Durante el evento se agradeció el tener varios momentos en los que era sencillo disfrutar del networking.&lt;/p&gt;

&lt;p&gt;El desayuno y la comida (compuesta básicamente por pequeños snacks de la mano de un catering) se ofrecían en mesas repartidas en dos salas. Todo el mundo se dirigía a picar algo de pie mientras charlaba. Se generaba buen ambiente y se abrían las puertas al networking. Por no mencionar que la comida estaba genial!&lt;/p&gt;

&lt;p&gt;Además, siempre estaban disponibles la máquina de café y algunos refrigerios para todo aquél que se quedase fuera de una charla mientras conversaba con otros asistentes.&lt;/p&gt;

&lt;p&gt;La primera noche del evento se organizó una gran cena en un enorme local muy cerca del evento, a la que asistió casi todo el mundo. Ello permitió que el primer día no acabase a las 19h00 como marcaba la agenda, sino que se extendió hasta bastante tarde (de madrugada para los valientes ;). La cena ayudó a que se dieran más oportunidades para conocer gente y en general aumentó la sensación de participación en el evento más allá de lo que es asistir a las charlas.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/6db0f48d11.jpg&quot; alt=&quot;6db0f48d11&quot; /&gt;
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;charlas-a-las-que-asistimos&quot;&gt;Charlas a las que asistimos&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Néstor Salceda&lt;/strong&gt;: &lt;em&gt;Experiencias con Interaction Driven Design.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Néstor nos contó la experiencia de su grupo usando Interaction Driven Design. Nos sorprendió muy gratamente observar cómo grupos distintos, que no tienen mucha comunicación de forma regular, hayan llegado a conclusiones tan similares en el uso de esta arquitectura.&lt;/p&gt;

&lt;p&gt;Nos valió para confirmar muchas de nuestras propias ideas. Una charla realmente agradable donde varias personas se animaron a poner código para mostrarnos sus aproximaciones y recibir feedback, entre ellos Alfredo y Ronny.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Carlos Villuendas&lt;/strong&gt;: &lt;em&gt;Reactjs desde las trincheras, un año después&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Carlos asistió el año pasado al evento dando la primera parte de esta charla. En ella comentaba que Fotocasa se había propuesto emplear React.js como librería de Frontend. Un año más tarde, vuelve a comentar cómo ha sido la experiencia. Dando todo un manual en el uso de esta librería basándose en la propias vivencias de su grupo. Una charla genial donde Carlos se mostró dispuesto a explicar con detalle cada cosa que se le preguntaba. Muy inspiradora.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sergi González y Javier Ferrer&lt;/strong&gt;: &lt;em&gt;Desarrollar un chat con Scala, Akka y WebSockets desde 0. ¡¿Qué puede salir mal?!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sergi y Javi nos contaron como en su empresa surgió la necesidad de meter en la aplicación un chat. Ello llevó a una primera implementación de un legacy escrito en PHP y cómo las necesidades de escalabilidad les plantearon usar modelo de actores con Akka y usar Scala como lenguaje de desarrollo. Empezando con una visión pero gran desconocimiento sobre el tema, consiguieron terminarlo después de un año y nos sirven de toda esa experiencia para hablarnos sobre ello, y acabar con nuestras mentes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Joel Rodríguez&lt;/strong&gt;: &lt;em&gt;Embracing flow for maximum productivity&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Joel nos estuvo contando la complejidad que implica alcanzar el flow y las tácticas que le han resultado efectivas en su experiencia. El flow siempre es algo que nos parece muy abstracto pero que sabemos detectar cuando lo estamos experimentando. Joel intenta convertirlo en algo que alcancemos de forma más consciente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Xavi Gost&lt;/strong&gt;: &lt;em&gt;CDD (Desarrollo dirigido por consenso)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Xavi nos estuvo explicando cómo están aplicando esta filosofía de equipo en Flywire. A destacar el rechazo del argumento de autoridad, que implica no obedecer ciegamente a otra persona con mayor autoridad. El argumento siempre debería ser analizado y contra argumentado si fuera necesario, siempre dentro de lo razonable. Rechazar un argumento de autoridad no significa rechazar una mayor experiencia. De forma muy resumida, los equipos están organizados en squads que hacen pairing y no se hacen Pull Requests, sino que todos los miembros del equipo leen el código y son libres de añadir un Concern en una feature que se debatirá en la siguiente Code Review. Se estimula la propiedad colectiva del código y el ambiente de equipo. Una charla que nos aportó mucho valor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vaughn Vernon&lt;/strong&gt;: &lt;em&gt;Event Storming for Fun and Profit&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;En este workshop de dos horas, Vernon nos brindó una sesión de Event Storming. Esta práctica de descubrimiento de dominio propuesta por Alberto Brandolini, consiste en unir a Product Owners y desarrolladores para crear algo parecido a un diagrama de eventos que nos permite identificar las acciones más importantes de una parte o todo nuestro negocio.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/2520bced6c.jpg&quot; alt=&quot;2520bced6c&quot; /&gt;
    &lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Los asistentes nos dividimos en tres grupos donde modelamos un dominio a nuestra elección. La sesión fue muy divertida y los asistentes del grupo en el que estábamos salieron muy satisfechos con la actividad. Sin duda una práctica muy valiosa para descubrir negocio y que pondremos más en práctica.&lt;/p&gt;

&lt;h3 id=&quot;participación-de-codesai&quot;&gt;Participación de Codesai&lt;/h3&gt;

&lt;p&gt;Varios de nosotros tuvimos una o más charlas durante el evento. Carlos rompió el hielo a primera hora del primer día dando su charla &lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=H_9g85X2MaE&quot;&gt;Designing in the Small. Principles and Practices.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Durante el mismo día Alfredo dio una charla sobre &lt;strong&gt;Connascense&lt;/strong&gt; (que iba a presentar junto con Fran, que no pudo asistir al evento) hablando de los distintos tipos de acoplamiento que podemos tener en cuenta para buscar heurísticas con las que evaluar nuestro código.&lt;/p&gt;

&lt;p&gt;Alfredo también participó en el OpenSpace, proponiendo una sesión sobre Microservicios. Durante una de las Lightning Talk, surgió este tema y se notaba que la gente se quedó con ganas de más. Por ello, la sala estaba a reventar y Alfredo se ofreció a empezar el debate en inglés dado que varios asistentes eran nativos. Una charla muy medida y en la que todos salieron muy contentos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/936382649d.jpg&quot; alt=&quot;936382649d&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/5abd54c406.jpg&quot; alt=&quot;5abd54c406&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Entre las Lightning Talks, Luis dió una sobre la toma de decisiones en un proyecto que tiene problemas, cómo ser eficiente en la práctica, dando varios puntos y consejos basados en su propia experiencia. Dani dió otra sobre el tema de Lectura Rápida, desmitificando algunos métodos y clarificando cómo la estaba practicando, recomendando su bibliografía.&lt;/p&gt;

&lt;p&gt;Luis también facilitó la Kata Potter en el Open Space junto con &lt;a href=&quot;https://twitter.com/alvarobiz&quot;&gt;Álvaro García&lt;/a&gt;. La retrospectiva de la kata se comió casi el siguiente slot de tiempo pues hubo un contraste de estilos muy interesante.&lt;/p&gt;

&lt;p&gt;Y muchas gracias a &lt;a href=&quot;/#team&quot;&gt;los compañeros de Codesai&lt;/a&gt; que se repartieron la asistencia a las charlas para luego poner en común lo aprendido, o que las dejaron pasar para hacer networking. ¡Día a día mejoramos como equipo!&lt;/p&gt;
</description>
          <pubDate>2016-11-02T16:14:56+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/11/estuvimos-en-la-software-craftsmanship-bcn-2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/11/estuvimos-en-la-software-craftsmanship-bcn-2016</guid>
        </item>
      
    
      
        <item>
          <title>Using coeffects in re-frame</title>
          <description>&lt;p&gt;Event handlers, collectively, provide the control logic in a &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt; application. Since the mutation of the &lt;strong&gt;application state&lt;/strong&gt; is taken care of by &lt;strong&gt;re-frame&lt;/strong&gt;, 
these &lt;strong&gt;event handlers&lt;/strong&gt; can be pure functions that given the current value of 
the &lt;strong&gt;application state&lt;/strong&gt; as first argument and the event (with its payload)
as second argument, provide a new value for the &lt;strong&gt;application state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is important because the fact that event handlers are pure functions brings great advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://xivilization.net/~marek/blog/2015/02/06/avoiding-action-at-a-distance-is-the-fast-track-to-functional-programming/&quot;&gt;&lt;strong&gt;Local reasoning&lt;/strong&gt;&lt;/a&gt;, which decreases the cognitive load required to understand the code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easier testing&lt;/strong&gt;, because pure functions are much easier to test.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Events replay-ability&lt;/strong&gt;, you can imagine a &lt;strong&gt;re-frame&lt;/strong&gt; application as a &lt;strong&gt;reduce&lt;/strong&gt; (&lt;a href=&quot;https://en.wikipedia.org/wiki/Fold_(higher-order_function)&quot;&gt;left fold&lt;/a&gt;) that proceeds step by step.
    Following this mental model, at any point in time, the value of the &lt;strong&gt;application state&lt;/strong&gt;
    would be the result of performing a &lt;strong&gt;reduce&lt;/strong&gt; over the entire collection of events dispatched 
    in the application up until that time, being the combining function for this &lt;strong&gt;reduce&lt;/strong&gt; 
    the set of registered event handlers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;However, to build a program that does anything useful, it’s inevitable to have some &lt;a href=&quot;http://blog.jenkster.com/2015/12/what-is-functional-programming.html&quot;&gt;&lt;strong&gt;side-effects&lt;/strong&gt; and/or &lt;strong&gt;side-causes&lt;/strong&gt;&lt;/a&gt;. So, there would be cases in which &lt;strong&gt;event handlers&lt;/strong&gt; won’t be pure functions.&lt;/p&gt;

&lt;p&gt;In this post, we’ll focus on &lt;strong&gt;side-causes&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“&lt;strong&gt;Side-causes&lt;/strong&gt; are data that a function, when called, needs but aren’t in its argument list. They are &lt;strong&gt;hidden or implicit inputs&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s see an example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/40e8c901e151a0c724e683a3e937c9aa.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The event handler for the &lt;strong&gt;:word-ready-to-check event&lt;/strong&gt;, that we are registering using &lt;strong&gt;reg-event-db&lt;/strong&gt;, is not pure because it’s using the value returned by JavaScript’s &lt;strong&gt;Date.now&lt;/strong&gt; function instead of getting it through its arguments. To make matters worse, in this particular case, this &lt;strong&gt;side-cause&lt;/strong&gt; also makes the event handler &lt;strong&gt;untestable&lt;/strong&gt; because JavaScript’s &lt;strong&gt;Date.now&lt;/strong&gt; function returns a different value each time it’s called.&lt;/p&gt;

&lt;p&gt;To be able to test this event handler we’ll have to somehow &lt;strong&gt;stub&lt;/strong&gt; the function that produces the &lt;strong&gt;side-cause&lt;/strong&gt;. In ClojureScript, there are many ways to do this (using &lt;a href=&quot;https://clojuredocs.org/clojure.core/with-redefs&quot;&gt;with-redefs&lt;/a&gt;, &lt;a href=&quot;https://clojuredocs.org/clojure.core/with-bindings&quot;&gt;with-bindings&lt;/a&gt;, a &lt;a href=&quot;http://martinfowler.com/bliki/TestDouble.html&quot;&gt;&lt;strong&gt;test doubles&lt;/strong&gt;&lt;/a&gt; library like &lt;a href=&quot;https://github.com/circleci/bond&quot;&gt;CircleCI’s bond&lt;/a&gt;, injecting and stubbing the dependency, etc.).&lt;/p&gt;

&lt;p&gt;In this example, we chose to make the dependency that the handler has on a function that returns the &lt;strong&gt;current timestamp&lt;/strong&gt; explicit and inject it into the &lt;strong&gt;event handler&lt;/strong&gt; which becomes a &lt;strong&gt;higher order function&lt;/strong&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/16010b7a4feca5961d80b2e57cbfd12c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In the previous code example, notice that the &lt;strong&gt;event handler&lt;/strong&gt; now receives as its first parameter a function that returns the &lt;strong&gt;current timestamp&lt;/strong&gt;, &lt;strong&gt;time-fn&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And this would be how before registering that event handler with &lt;strong&gt;reg-event-db&lt;/strong&gt;, we perform a &lt;strong&gt;partial application&lt;/strong&gt; to inject JavaScript’s &lt;strong&gt;Date.now&lt;/strong&gt; function into it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/da335e6e6a254e13b5ab707f858890ef.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Using the same technique, we can now &lt;strong&gt;inject a stub of the time-fn function&lt;/strong&gt; into the event handler in order to test it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ed389cefd49f8961b16da4bfc8dfc32e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is the code of the home-made &lt;strong&gt;factory&lt;/strong&gt; to create &lt;strong&gt;stubs&lt;/strong&gt; for &lt;strong&gt;time-fn&lt;/strong&gt; that we used in the previous test:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f8ae9b12ac225b87ab3c9c3c21dc5c57.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;We’ve seen how using a &lt;strong&gt;test double&lt;/strong&gt; makes the event handler testable again, but at the price of introducing more complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bottom line problem is that the event handler is not a pure function&lt;/strong&gt;. This makes us lose not only the &lt;strong&gt;easiness of testing&lt;/strong&gt;, as we’ve seen, but also the rest of advantages cited before: &lt;strong&gt;local reasoning&lt;/strong&gt; and &lt;strong&gt;events replay-ability&lt;/strong&gt;. It would be great to have &lt;strong&gt;a way to keep event handlers pure, in the presence of side-effects and/or side-causes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/CHANGES.md&quot;&gt;re-frame’s 0.8.0 (2016.08.19) release&lt;/a&gt;, this problem has been solved by introducing the concept of &lt;strong&gt;effects&lt;/strong&gt; and &lt;strong&gt;coeffects&lt;/strong&gt;. &lt;strong&gt;Effects&lt;/strong&gt; represent what your program does to the world (&lt;strong&gt;side-effects&lt;/strong&gt;) while &lt;strong&gt;coeffects&lt;/strong&gt; track what your program requires from the world (&lt;strong&gt;side-causes&lt;/strong&gt;). Now we can write &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/EffectfulHandlers.md&quot;&gt;effectful event handlers&lt;/a&gt; that keep being pure functions.&lt;/p&gt;

&lt;p&gt;Let’s see how to use &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md&quot;&gt;coeffects&lt;/a&gt; in the previous event handler example. As we said, &lt;strong&gt;coeffects track side-causes&lt;/strong&gt;, (see for a more formal definition &lt;a href=&quot;http://tomasp.net/blog/2014/why-coeffects-matter/&quot;&gt;Coeffects The next big programming challenge&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;At the beginning, we had this &lt;strong&gt;impure event handler&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/40e8c901e151a0c724e683a3e937c9aa.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;then we wrote a &lt;strong&gt;testable but still impure version&lt;/strong&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/16010b7a4feca5961d80b2e57cbfd12c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md&quot;&gt;coeffects&lt;/a&gt;, we can eliminate the  &lt;strong&gt;side-cause&lt;/strong&gt;, passing the &lt;strong&gt;timestamp input&lt;/strong&gt; through the argument list of the event handler. The resulting event handler is a pure function:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/ae7258c39d91dcaf540c1617c2c13077.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This event handler receives, as its first parameter, &lt;strong&gt;a map of coeffects&lt;/strong&gt;, &lt;strong&gt;cofx&lt;/strong&gt;, which contains &lt;strong&gt;two coeffects&lt;/strong&gt;, represented as key/value pairs. One of them is the &lt;strong&gt;current timestamp&lt;/strong&gt; which is associated to the &lt;strong&gt;:timestamp&lt;/strong&gt; key, and the other one is the &lt;strong&gt;application state&lt;/strong&gt; associated to the &lt;strong&gt;:db&lt;/strong&gt; key. The second argument is, as in previous examples, the event with its payload.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;map of coeffects&lt;/strong&gt;, &lt;strong&gt;cofx&lt;/strong&gt;, is the complete set of inputs required by the event handler to perform its computation. Notice how &lt;strong&gt;the application state is just another coeffect&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the same event handler but using &lt;a href=&quot;http://garajeando.blogspot.com.es/2014/12/talk-about-clojure-destructuring.html&quot;&gt;destructuring&lt;/a&gt; (which is how I usually write them):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/153b3d36687091d6ec8d073f70a6f812.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;How does this work? How does the &lt;strong&gt;coeffects map&lt;/strong&gt; get passed to the event handler?&lt;/p&gt;

&lt;p&gt;We need to do two things previously:&lt;/p&gt;

&lt;p&gt;First, we register the event handler using &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md&quot;&gt;re-frame’s &lt;strong&gt;reg-event-fx&lt;/strong&gt;&lt;/a&gt; instead of &lt;strong&gt;reg-event-db&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you use &lt;strong&gt;reg-event-db&lt;/strong&gt; to associate an &lt;strong&gt;event id&lt;/strong&gt; with the function that handles it, its &lt;strong&gt;event handler&lt;/strong&gt;, that &lt;strong&gt;event handler&lt;/strong&gt; gets as its first argument, the &lt;strong&gt;application state&lt;/strong&gt;, &lt;strong&gt;db&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While event handlers registered via &lt;strong&gt;reg-event-fx&lt;/strong&gt; also get two arguments, the first argument is a &lt;strong&gt;map of coeffects&lt;/strong&gt;, &lt;strong&gt;cofx&lt;/strong&gt;, instead of the &lt;strong&gt;application state&lt;/strong&gt;. The &lt;strong&gt;application state&lt;/strong&gt; is still passed in the &lt;strong&gt;cofx&lt;/strong&gt; map as a &lt;strong&gt;coeffect&lt;/strong&gt; associated to the &lt;strong&gt;:db&lt;/strong&gt; key, it’s just another &lt;strong&gt;coeffect&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is how the previous pure event handler gets registered:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/c3c14ba3ea8ef63100b8a1d0b7c955a8.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice the second parameter passed to &lt;strong&gt;reg-event-fx&lt;/strong&gt;. This is an optional parameter which is a vector of &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Interceptors.md&quot;&gt;interceptors&lt;/a&gt;. Interceptors are functions that wrap event handlers implementing middleware by assembling functions, as data, in a collection. They “can look after cross-cutting concerns helping to “factor out commonality, hide complexity and introduce further steps into the &lt;strong&gt;‘Derived Data, Flowing’ story&lt;/strong&gt; promoted by &lt;strong&gt;re-frame&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;In this example, we are passing an interceptor created using &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md&quot;&gt;re-frame’s &lt;strong&gt;inject-cofx&lt;/strong&gt;&lt;/a&gt; function which returns an interceptor that will load a key/value pair (coeffect id/coeffect value) into the &lt;strong&gt;coeffects map&lt;/strong&gt; just before the event handler is executed.&lt;/p&gt;

&lt;p&gt;Second, we &lt;strong&gt;factor out the coeffect handler&lt;/strong&gt;, and then register it using &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md&quot;&gt;re-frame’s &lt;strong&gt;reg-cofx&lt;/strong&gt;&lt;/a&gt;. This function associates a &lt;strong&gt;coeffect id&lt;/strong&gt;  with the function that injects the corresponding key/value pair into the &lt;strong&gt;coeffects map&lt;/strong&gt;. This function is known as the &lt;strong&gt;coeffect handler&lt;/strong&gt;. For this example, we have:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5ce7ace9f05552bc6609afcc475efb5f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Since the event handler is now a pure function, it becomes very easy to test it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/374e323a279c32274473f84aa97631ee.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Notice how we don’t need to use &lt;strong&gt;tests doubles&lt;/strong&gt; anymore in order to test it. Thanks to the use of &lt;strong&gt;coeffects&lt;/strong&gt;, the event handler is a pure function, and we can just pass any timestamp to it in its arguments.&lt;/p&gt;

&lt;p&gt;More importantly, we’ve also regained the advantages of &lt;strong&gt;local reasoning&lt;/strong&gt; and &lt;strong&gt;events replay-ability&lt;/strong&gt; that comes with having &lt;strong&gt;pure event handlers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In future posts, we’ll see how we can do something similar using &lt;a href=&quot;https://github.com/Day8/re-frame/blob/master/docs/Effects.md&quot;&gt;&lt;strong&gt;effects&lt;/strong&gt;&lt;/a&gt; to keep events handlers pure in the presence of &lt;strong&gt;side-effects&lt;/strong&gt;.&lt;/p&gt;
</description>
          <pubDate>2016-10-24T22:17:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/10/using-coeffects-in-re-frame</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/10/using-coeffects-in-re-frame</guid>
        </item>
      
    
      
        <item>
          <title>Refactoring tests using builder functions in Clojure/ClojureScript</title>
          <description>&lt;p&gt;
  Using literals in your tests can have some advantages, such as, readability and traceability. 
&lt;/p&gt;

&lt;p&gt;
  While this is true when the data are simple, it&apos;s less so when the data are nested, complex structures.
In that case, using literals can hinder refactoring and thus become an obstacle to adapting to changes.
&lt;/p&gt;

&lt;p&gt;
  The problem with using literals for complex, nested data is that the knowledge about how to build such data is spread all over the tests. There are many tests that know about the representation of the data.
&lt;/p&gt;

&lt;p&gt;
  In that scenario, nearly any change in the representation of those data will have a big impact on the tests code because it will force us to change many tests.
&lt;/p&gt;

&lt;p&gt;
  This is an example of a test using literals, (from a ClojureScript application
using &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;, I&apos;m developing with my colleague &lt;a href=&quot;https://twitter.com/zesc&quot;&gt;Francesc&lt;/a&gt;), to prepare the &lt;i&gt;application state&lt;/i&gt; (usually called &lt;i&gt;db&lt;/i&gt; in &lt;a href=&quot;https://github.com/Day8/re-frame&quot;&gt;re-frame&lt;/a&gt;):
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/50a48e7899ba820ca140835112e8ad0b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  As you can see, this test knows to much about the structure of &lt;i&gt;db&lt;/i&gt;. 
&lt;/p&gt;

&lt;p&gt;
  There were many other tests doing something similar at some nesting level of the &lt;i&gt;db&lt;/i&gt;. 
&lt;/p&gt;

&lt;p&gt;
  To make things worse, at that moment, we were still learning a lot about the domain, so the structure of the &lt;i&gt;db&lt;/i&gt; was suffering changes with every new thing we learned. 
&lt;/p&gt;

&lt;p&gt;
  The situation was starting to be painful, since any refactoring provoke many changes in the tests, so we decided to fix it.
&lt;/p&gt;

&lt;p&gt;
  What we wanted was a way to place all the knowledge about the representation of the &lt;i&gt;db&lt;/i&gt; in just one place (i.e., remove duplication), so that, in case we needed to change that representation, the impact of the change would be absorbed by changing only one place.
&lt;/p&gt;

&lt;p&gt; 
  A nice way of achieving this goal in object-oriented code, and at the same time making your tests code more readable, is by using &lt;a href=&quot;http://www.natpryce.com/articles/000714.html&quot;&gt;test data builders&lt;/a&gt; which use the &lt;a href=&quot;https://en.wikipedia.org/wiki/Builder_pattern&quot;&gt;builder pattern&lt;/a&gt;, but how can we do these &lt;i&gt;builders&lt;/i&gt; in Clojure?
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://aphyr.com/posts/321-builders-vs-option-maps&quot;&gt;Option maps or function with keyword arguments are a nice alternative&lt;/a&gt; to traditional builders in dynamic languages such as Ruby or Python.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;http://stackoverflow.com/questions/12633670/whats-the-clojure-way-to-builder-pattern&quot;&gt;In Clojure we can compose &lt;i&gt;functions with keyword arguments&lt;/i&gt; to get very readable builders&lt;/a&gt; that also hide the representation of the data.
&lt;/p&gt;

&lt;p&gt;
  We did TDD to write these &lt;i&gt;builder functions&lt;/i&gt;. These are the tests for one of them, the &lt;i&gt;db builder&lt;/i&gt;:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/093f10a3af82422d1eff8a83323aa7a7.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  and this is the &lt;i&gt;db builder&lt;/i&gt; code:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/1832b30d4a397acc0d24c3659edf1161.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  which is using &lt;a href=&quot;http://clojure.org/guides/destructuring&quot;&gt;associative destructuring&lt;/a&gt; on the function&apos;s optional arguments to have a function with keyword arguments, and creating proper default values using the &lt;i&gt;:or keyword&lt;/i&gt; (have a look at the &lt;a href=&quot;https://gist.github.com/trikitrok/e24b0a8ecacf8c1ae726&quot;&gt;material of a talk about destructuring I did some time ago&lt;/a&gt; for &lt;a href=&quot;http://www.meetup.com/ClojureBCN/&quot;&gt;Clojure Barcelona Developers community&lt;/a&gt;).
&lt;/p&gt;

&lt;p&gt;
  After creating &lt;i&gt;builder functions&lt;/i&gt; for some other data used in the project, our test started to read better and to be robust against changes in the structure of &lt;i&gt;db&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
  For instance, this is the code of the test I showed at the beginning of the post, but now using &lt;i&gt;builder functions&lt;/i&gt; instead of literals:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e8a8244ebc0fa82352bb8003a82da077.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  which not only hides the representation of &lt;i&gt;db&lt;/i&gt; but also eliminates details that are not used in particular tests, while still being as easy to read, if not easier, than the version using literals.
&lt;/p&gt;

&lt;p&gt;
  We have seen how, by composing &lt;i&gt;builder functions&lt;/i&gt; and using them in our tests, we managed to reduce the impact surface of changes in the representation of data might have on our tests. &lt;i&gt;Builder functions&lt;/i&gt; absorb the impact of those changes, and enable faster refactoring, and, by doing so, enable us to adapt to changes faster.
&lt;/p&gt;
</description>
          <pubDate>2016-10-07T22:17:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/10/refactoring-tests-using-builder-functions-in-clojure-clojureScript</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/10/refactoring-tests-using-builder-functions-in-clojure-clojureScript</guid>
        </item>
      
    
      
        <item>
          <title>Muchas gracias Modesto</title>
          <description>&lt;p&gt;
  Hace unas semanas recibimos una noticia con sabor agridulce. Nuestro gran compañero y mejor profesional, Modesto, se marcha de Codesai. No resulta fácil perder a un compañero del que todos aprendemos muchísimo y que siempre está apoyando al equipo ante cualquier dificultad. Pero la verdad es que nos alegramos de que pueda tomar el rumbo que más le beneficie en este momento. Nuestra relación no se ve afectada en absoluto y seguiremos aprendiendo juntos en los eventos de comunidad y meetups de Codesai. Las puertas siempre están abiertas para Modesto. Han sido dos años estupendos trabajando juntos, ¡hasta compartiendo piso!
&lt;/p&gt;

&lt;p&gt;Modesto habla de la experiencia en &lt;a href=&quot;http://www.modestosanjuan.com/nuevos-retos/&quot; &gt;un post en su blog&lt;/a&gt;. Queremos aprovechar para escribir un pequeño homenaje como muestra de agradecimiento por su entrega y su aporte a todo el equipo. Esto es lo que cada uno de nosotros dice:
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Carlos:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  He conocido a pocas personas capaces de aprender y asimilar tan rápido como Modesto. Con capacidad de sacarle infinidad de horas de rendimiento al día. Es rápido y eficaz ofreciendo soluciones. No sé cómo le da tiempo a leer tanto. Contar con él como experto en la plataforma .Net suponía una tranquilidad que no tiene precio. Se nos va uno de nuestros mayores tecnólogos. Solo espero que volvamos a coincidir pronto y que le vaya de maravilla.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Fran:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Pragmatismo y capacidad de aprender a un ritmo increíble son dos de las cosas que me llegan a la cabeza cuando intento definir alguna de las cualidades de Modesto como profesional. Sus conocimientos en tecnologías de Microsoft son un seguro de vida para embarcarte en un proyecto que trate con ellas sin temer por su tamaño. Su humor y las ganas de debatir siempre hacen que cualquier charla deje de convertirse en banal para tornarse en alguna discusión interesante. He aprendido mucho estos años de él dentro de Codesai y espero que, aunque quizás con menos frecuencia, lo siga haciendo. No hace falta que le desee suerte allá dónde vaya, ya lleva una mochila repleta de habilidades y experiencias para hacer lo que le apasione.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Alfredo:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Hace ya dos años, madre mía como pasa el tiempo de rápido!, nos juntamos cuatro locos para colaborar y trabajar juntos en un proyecto con mucha incertidumbre y muchas incógnitas, ni cortos ni perezosos cogimos las maletas y allá aparecimos en las palmas. Uno de esos locos era Modesto, y sin duda gracias a sus aportaciones ese proyecto hoy podemos apuntarlo en la libreta de éxitos profesionales y también en la de los personales. Sus conocimientos de .NET han sido fundamentales para compensar las carencias que otros teníamos,  no deja de ser sorprendente ver como al final la tecnología es solo un detalle y lo que nos une como profesionales esta en la pasión por nuestro trabajo y en las prácticas y los principios esos que tan pesados somos repitiendo y no voy a enumerar ahora.  Mucha suerte en tus proyectos futuros!, y para terminar tópicazo: esto no es un adios es un hasta luego, porque al final este mundo nuestro es más pequeño de lo que parece y el camino del craftsman  esta lleno de cruces e intersecciones.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Luis:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  No me cabe la menor duda que Modesto disfrutará y dejará huella allí donde esté. A mí me gustaría destacar su lado humano: la capacidad de ponerse en el lugar del otro y hablar desde ahí. Con una facilidad para hablar claro y mantener un debate profundo a la vez que aportar toques de humor cuando hay que relajar el ambiente. Muchas gracias por tu disposición a echar una mano siempre. Nos vemos en el camino.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Ronny:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Hablar de Modesto para mí es en primer lugar hablar de una persona a la que aprecio muchísimo. Desde el día que lo conocí en un coding dojo hasta hoy que escribo esto, no he parado de aprender de él. Sin duda, es una de las personas más inteligentes que conozco, pero si hay algo que me gustaría resaltar de él, es su pasión por el software. Me ha transmitido grandes valores como la humildad y la transparencia, aprender de Modesto no solo me ha hecho mejor programador sino que también me ha ayudado a ser mejor persona. Para mí es sin duda un ejemplo a seguir. La primera semana que estuvimos en el piso fue impresionante, la recuerdo perfectamente, buscamos un pet project, me enseñó a usar dobles de pruebas, me enseñó que eran los diagramas de secuencia y más. Pero eso no es todo, sino que ha medida que ha ido pasando el año, cada semana que hemos coincidido en el piso ha sido brutal. Aprender de alguien que es técnicamente tan bueno es increíble, hemos tenido mucha suerte de contar con él. Así que Modesto, me gustaría darte las gracias. Gracias por todo lo que me has transmitido este año, gracias por mostrarte siempre dispuesto a enseñarme, gracias por todos tus consejos y gracias por ser en definitiva una gran persona. Espero que te vaya muy bien en este próximo paso en tu camino (sé que así será).  Aunque profesionalmente hablando nuestros caminos se separen, para mí seguirás siendo siempre un mentor, un compañero en el camino del aprendizaje y sobre todo un gran amigo. Espero que sean excusas suficientes para seguir teniendo nuestras largas conversaciones sobre nuestra gran pasión. Además tenemos un pet project que mantener. Mucha suerte!
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Miguel:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Cuando pienso en Modesto siempre se me viene a la cabeza, la palabra fascinación. Fascinación por su conocimiento técnico, fascinación por las reflexiones personales que me ha brindado, fascinación por la pasión que trasmite con un teclado en las manos y fascinación porque solo necesita dormir 4 horas al día y estar más descansado que yo :P. Creo que como grupo hemos tenido mucha suerte de contar con tu presencia, no solo por la más que conocida capacidad técnica en .NET sino porque he aprendido que no hay que tener miedo a arremangarse y meterse en el fango para solventar problemas a los que preferirías no enfrentar y hacer otras cosas ya que puedes aportar valor en ese área. Me has enseñado a tener mucho más espectro en el significado de aportar valor y quiero agradecer la cantidad de horas que nos has dedicado con nuestros pet projects, de tener una duda a altas horas de la noche y conectarte a echar una mano y dar tu punto de vista y de no tratar de servirnos en bandeja la respuesta y dejarnos experimentar por el &quot;aprendizaje por dolor&quot;. Muchas gracias por todo y de verdad espero que como menciona Alfredo, nuestros caminos se vuelvan a cruzar porque un camino es siempre mejor si vas acompañado de personas fascinantes.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Dani:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Ahí donde vaya la conversación, Modesto siempre surge con un: &quot;Pues una vez hice eso&quot; o &quot;En tal momento trabajé en algo similar&quot;. Lleno de experiencia y con infinidad de recursos, dedicándole un buen cacho del día a seguir investigando temas, pero siempre con tiempo para responder una pregunta o echarte un cable con lo que sea. Coincidimos en muchas cosas y diferimos en otra tantas, una conversación con Modesto siempre es productiva y acabará con algo nuevo aprendido. Seguiremos charlando y nos seguiremos viendo ;), muchas gracias por todo!
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Jose:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Personalmente, cuando pienso en Modesto, una de las primeras cosas que se me vienen a la mente es su experiencia y su capacidad de resolución. Me hubiera encantado haber trabajado en algún proyecto con él, aunque lamentablemente no ha podido ser así. Independientemente a ello, considero que he aprendido mucho de él, ya que en cada conversación con Modesto obtienes nuevos conocimientos.
&lt;/p&gt;

&lt;p&gt;
  A todo esto, muchas gracias por todo Modesto, por compartir tus conocimientos y experiencias con nosotros. Es una pena que te vayas del equipo, no obstante, espero que tengas mucha suerte en tu nueva etapa y que todo te vaya muy bien.
&lt;/p&gt;

&lt;br/&gt;&lt;strong&gt;Antonio:&lt;/strong&gt;&lt;br/&gt;
&lt;p&gt;
  Esta debe ser la cuarta vez que empiezo mi parte de este post porque todos me suenan a epitafio.&lt;br /&gt;
Supongo que es porque tengo una gran sensación de pérdida y hoy sin ir más lejos, pegándome con .NET creo que vamos a echar de menos su conocimiento en el equipo.
&lt;/p&gt;
&lt;p&gt;
  Gracias Modesto por esas conversaciones profundas. Y por enseñarme que después de un buen intercambio dialéctico se puede tener el coraje y la humildad de reconocer cuando se ha cambiado de opinión. Muy pocas veces he visto eso.
&lt;/p&gt;

&lt;p&gt;¡Ala! ¡Mucha suerte en tu nueva etapa y a dar guerra en la comunidad!&lt;/p&gt;
</description>
          <pubDate>2016-10-07T15:57:39+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/10/muchas-gracias-modesto</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/10/muchas-gracias-modesto</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Habitissimo</title>
          <description>&lt;p&gt;
  Gracias a &lt;a href=&quot;https://twitter.com/voylinux&quot; &gt;Pablo Bernardo&lt;/a&gt; y &lt;a href=&quot;https://twitter.com/jordillull&quot; &gt;Jordi Llull&lt;/a&gt; de &lt;a href=&quot;https://www.habitissimo.es/&quot; &gt;Habitissimo&lt;/a&gt;, pudimos disfrutar de tres días de trabajo y conferencias en Palma de Mallorca, en el ParcBit. Fuimos Luis Rovirosa y yo a impartir una formación de TDD y Clean Code para 15 developers entusiasmados con aprender. Nos sorprendió gratamente el ambientazo de trabajo tan bueno que se respira allí y lo chula que es la oficina, con sus salas temáticas para reuniones, ocio y hasta espacio para meditación. La gente tenía muy interiorizado lo de ser productivo con la herramienta, manejaban casi todo con shortcuts, los entornos de desarrollo eran rápidos y pulidos... gente muy joven con una capacidad de aprendizaje muy alta, las pillaban al vuelo.
&lt;/p&gt;

&lt;img src=&quot;/assets/photo_2016-10-07_12-58-38-1024x768.jpg&quot; alt=&quot;programmers working during course&quot; /&gt;

&lt;p&gt;
  Durante la formación hicimos pair programming de una manera bastante ergonómica con dos teclados, dos ratones y dos pantallas conectadas a cada máquina. El espacio de trabajo quedaba muy cómodo tanto para los participantes como para nosotros que paseábamos por detrás observándoles trabajar o participando en las discusiones.
  &lt;br /&gt;
  Lo pasamos muy bien.
&lt;/p&gt;

&lt;p&gt;
  Conocer y trabajar para Habitissimo era especialmente atractivo para mí porque en 2010 nosotros habíamos emprendido con Maven Charts, la misma idea de Habitissimo, pero que no conseguimos rentabilizar. Aprendimos muchísimo pero económicamente fracasamos. Ver que a pesar de toda la competencia y de lo difícil que se presentaba el mercado nacional, alguien había conseguido hacer triunfar la idea, me alegra mucho. Fue un placer conocer a los fundadores y charlar un ratito con ellos. En cierto modo era como ver &quot;mi idea&quot; triunfar. 
&lt;/p&gt;

&lt;img src=&quot;/assets/habitissimo_14360167_901899213287787_1124782772964032512_n.jpg&quot; alt=&quot;Code Retreat&quot; /&gt;
  
&lt;p&gt;
  El último día tuvo lugar un Code Retreat abierto a todo el mundo donde vino mucha gente para ser un día laboral, fue todo un éxito de convocatoria y lo pasamos muy bien. Por la tarde hubieron conferencias pero como teníamos vuelo nos quedamos con la pena de ver solamente una, la de &lt;a href=&quot;https://twitter.com/jllado&quot; &gt;Juan Lladó&lt;/a&gt; sobre su experiencia con TDD, charla que me gustó mucho. Yo abrí la jornada de charlas con una sobre diseño.
&lt;/p&gt;

&lt;img src=&quot;/assets/CuKcgJJWcAAQZoz.jpg&quot; alt=&quot;Carlos y Luis&quot;/&gt;

&lt;p&gt;
  En una de las salas de ocio había una hamaca y enseguida me acordé del &lt;a href=&quot;https://www.youtube.com/watch?v=dYBjVTMUQY0&quot; &gt;video de Atlassian Spooning&lt;/a&gt; así que nos queda una foto para el recuerdo gracioso. No sé si después de mostrarles el vídeo harán spooning en la hamaca :-D
&lt;/p&gt;
</description>
          <pubDate>2016-10-07T11:39:27+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/10/estuvimos-en-habitissimo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/10/estuvimos-en-habitissimo</guid>
        </item>
      
    
      
        <item>
          <title>Lo que me aporta TDD</title>
          <description>&lt;p&gt;
  Hace tiempo que vengo queriendo reescribir nuestro libro de TDD para mejorarlo con todo lo que hemos aprendido en estos 7 años y todo el feedback que hemos recibiendo por parte de los lectores, a los cuales estamos muy agradecidos. Pero no se cuándo me podré sentar durante un puñado de meses a abordar semejante reto.
&lt;/p&gt;

&lt;p&gt;
  Sin embargo, los atículos y críticas destructivas que se leen sobre esta práctica de vez en cuando, tanto en inglés como en castellano, hacen que me apetezca volver a hablar de lo mucho que me aporta esta práctica.
&lt;/p&gt;

&lt;h2&gt;Lo que me aporta TDD&lt;/h2&gt;

&lt;p&gt;
  A los programadores nos encanta el &lt;strong&gt;feedback rápido&lt;/strong&gt;, todos los que disponemos de algún &lt;a href=&quot;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&quot; &gt;REPL&lt;/a&gt; en nuestro lenguaje, estamos encantados. En el browser es facilísimo abrir la consola para escribir una línea de JavaScript y averiguar si determinada expresión se evalúa como creemos. Igual pasa con las consolas de Ruby y de Python. Hasta para C# suelo tirar de &lt;a href=&quot;http://csharppad.com/&quot; &gt;C# Pad&lt;/a&gt; muchas veces, y de &lt;em&gt;&quot;Inmmediate Window&quot;&lt;/em&gt; en VS. Hacer pruebas rápidas y pequeñas en un REPL es una forma de TDD a mi modo de ver. Te permite avanzar en pequeños pasos seguros. A veces practicando TDD escribo un test que poco más tarde borro, porque lo único que quería era feedback rápido, no pretendía dejar una prueba escrita.
&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-md-5&quot;&gt;
    &lt;figure&gt;
      &lt;img src=&quot;/assets/tdd-simple.svg&quot; alt=&quot;TDD Cycle&quot;/&gt; 
      &lt;figcaption&gt;&lt;strong&gt;TDD Cycle&lt;sup&gt;1&lt;/sup&gt;&lt;/strong&gt;&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
  &lt;div class=&quot;col-md-7&quot;&gt;
    &lt;p&gt;
      El otro gran beneficio que obtengo practicando TDD es la &lt;strong&gt;simplicidad&lt;/strong&gt;. Soy un experto complicándome la vida, pero gracias a la regla de escribir el código mínimo para que el test pase y nada más, consigo implementaciones mucho más simples de las que me quedaban antes. El prestar mucha atención a las generalizaciones progresivas, como dice &lt;a href=&quot;https://en.wikipedia.org/wiki/Transformation_Priority_Premise&quot; &gt;Transformation Priority Premise&lt;/a&gt;, hace que ahora use más veces la recursividad, en soluciones que naturalmente son recursivas. Antes simplemente me volvía loco con bucles. Un efecto secundario de ir al mínimo es que se me ocurren casos de uso que ni se me habían pasado por la cabeza, a veces casos límite. Es decir que el truco de hackear la implementación para que el test pase me hace ser consciente de casos importantes a cubrir, que quizás nunca hubiese tenido en cuenta. Por tanto me ayuda a encontrar problemas más temprano.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;
  TDD me obliga a &lt;strong&gt;pensar antes de codificar&lt;/strong&gt;. Si escojo un enfoque inside-out, tengo que haber descompuesto muy bien el problema antes para estar seguro que esa pieza de bajo nivel me va a encajar en el puzzle. Si escojo outside-in me obligo a pensar en dependencias, paso de mensajes, diseño orientado a objetos. Pienso que TDD no lleva a un buen diseño por sí, pero teniendo &lt;strong&gt;conocimientos de diseño&lt;/strong&gt;, me ayuda a detectar problemas en el mismo. Por ejemplo cuando me cuesta mucho escribir un test, es porque me faltan piezas en el diseño, porque el área que estoy explorando todavía no es la más adecuada, porque estoy introduciendo demasiada complejidad.... lo tomo como una pista para replantearme el camino elegido. Y acompañado además por los micro-commits, puedo volver atrás en cualquier momento y tomar otro camino de la solución.
&lt;/p&gt;

&lt;p&gt;
  JB Rainsberger &lt;a href=&quot;http://blog.thecodewhisperer.com/permalink/jmock-v-mockito-but-not-to-the-death&quot; &gt;dice por ejemplo&lt;/a&gt; que cuando hace TDD prefiere usar mocks en lugar de spies, porque los dolores a la hora de usar dobles son mas evidentes y eso le da más pistas sobre su diseño (ver los comentarios del post).
&lt;/p&gt;

&lt;p&gt;
  Con TDD no me atasco, el avance es constante, me permite entrar en &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Flow_(psychology)&quot; &gt;flow&lt;/a&gt;&lt;/strong&gt;. &lt;strong&gt;No tengo que depurar!&lt;/strong&gt; practicamente nunca tengo que depurar y cuando esto sucede es otra pista de que he dado un paso demasiado grande a la hora de descomponer el problema o de que necesito descansar porque hay un &lt;em&gt;typo&lt;/em&gt; muy chorra que no consigo encontrar.
&lt;/p&gt;

&lt;h2&gt;No vale para todo&lt;/h2&gt;

&lt;p&gt;
  Hay muchísimas situaciones en las que no hago TDD, por ejemplo cuando estudio una nueva tecnología o API de un tercero. &lt;strong&gt;Todo gira en torno al feedback, la simplicidad y la cadencia.&lt;/strong&gt; Cuando voy a poderle sacar partido lo uso y cuando no, pues no lo uso. Igual que ocurre con cualquier herramienta de las que tenemos disponibles. A veces al introducir una pequeña funcionalidad en un código existente o al hacer un pequeño cambio, consigo ir más rápido escribiendo el código primero, probando a mano la aplicación y después dejando un test automático de respaldo. Sucede tipicamente en sistemas legacy donde los tests tardan mucho en ejecutarse o es tan dificil de añadir un test que valido la hipótesis primero probando a mano y luego ya agregando el test.
&lt;/p&gt;

&lt;p&gt;
  Y tu que también practicas TDD, ayúdame a recordar más beneficios, deja un comentario please ;-)
&lt;/p&gt;

&lt;br/&gt; 

&lt;div class=&quot;foot-note&quot;&gt;
  &lt;sup&gt;1&lt;/sup&gt;Figure from Growing Object-Oriented Software by Nat Pryce and Steve Freeman.
&lt;/div&gt;</description>
          <pubDate>2016-10-07T10:04:16+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/10/lo-que-me-aporta-tdd</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/10/lo-que-me-aporta-tdd</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en la Tarugoconf</title>
          <description>&lt;h3&gt;¿Qué es la Tarugoconf?&lt;/h3&gt;

&lt;p&gt;
  El viernes pasado, 16 de septiembre de 2016, asistí como orgulloso representante de Codesai, al&lt;strong&gt; mejor evento posible que cupiese en la imaginación de &lt;a href=&quot;https://twitter.com/david_bonilla&quot; &gt;David Bonilla&lt;/a&gt;: la &lt;a href=&quot;http://www.tarugoconf.com/&quot; &gt;Tarugoconf&lt;/a&gt;.&lt;/strong&gt; Un evento que nunca hubiese existido si no le hubiesen dicho las tres palabras mágicas &quot;No hay huevos&quot; y que se construye bajo las siguientes premisas: Utilidad, Practicidad, Diversión y Calité.
&lt;/p&gt;

&lt;p&gt;Citando la web:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;¿Qué carallo es esto?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;
    Sólo 100 entradas a la venta. 1 sólo día, 1 sólo track y 1 sólo objetivo: crear el evento sobre construcción y comercialización de Productos Digitales más awesómico y gallego del mundo. Lleno de ponentes con muchos tiros pegaos en las barricadas del mundillo tecnológico y que, en sus charlas, intentarán responder una simple pregunta:
  &lt;/p&gt;
  &lt;p&gt;
    &lt;strong&gt;&lt;em&gt;¿Qué cambiaría si pudiera volver 2 años atrás?&lt;/em&gt;&lt;/strong&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;El previo&lt;/h3&gt;

&lt;img src=&quot;/assets/invitaciontarugoconf.png&quot; alt=&quot;Invitacion Tarugoconf&quot; /&gt;


&lt;p&gt;
  Cuando presentó el evento por primera vez e informó que &lt;strong&gt;las entradas iban a ser por invitación&lt;/strong&gt;, sabía que no iba a sentar bien y así fue. Escuché muchos comentarios y ninguno bueno; al que no le parecía innecesariamente exclusivo (como sinónimo de excluyente), le parecía que iba a ser carne delicatessen para trolls. Como reflexión David ya comentó, que para siguientes sólo una parte sería bajo invitación y el resto abierto a todo el mundo que quisiera venir.
&lt;/p&gt;

&lt;p&gt;
  A mi me parece un sistema tan bueno como cualquiera. Se quedó gente fuera, que hubiese pasado igual y en esta conferencia el tamaño sí importaba.
&lt;/p&gt;

&lt;p&gt;
  Ah! ¡Y el evento era dos días! Organizaron para el sábado una día de &apos;networking family friendly&apos; realmente prometedor. No lo disfruté, será para la próxima.
&lt;/p&gt;

&lt;h3&gt;El evento&lt;/h3&gt;

&lt;img src=&quot;/assets/tarugo_IMG_20160916_093256.jpg&quot; alt=&quot;Benvidos a la Tarugoconf!&quot;  /&gt;

&lt;p&gt;
  Y llegó el gran día. Registro y café con bollos con un ambiente algo festivo. Había gente de todo el ecosistema: desarrollo, coaching, empresa, StartUps, ... caras conocidas y no tanto que invitaban a saludarse. Había conexión.
&lt;/p&gt;

&lt;p&gt;
  Inaugura David con una minikeynote de 15 minutos en las que nos presenta la agenda, cosas prácticas como &lt;strong&gt;dónde estará la pulpeira&lt;/strong&gt;, cómo ir a la fiesta por la noche y lo más importante, la motivación de la conferencia y por qué estamos aquí hoy. Fue un momento con un montón de energía que nos ponía en situación de lo que iba a venir.
&lt;/p&gt;

&lt;p&gt;
  Para hacer el resumen siguiente me voy a fijar en &lt;a href=&quot;https://goo.gl/photos/Z1e53MuCXuv3cshT6&quot;&gt;mis notas&lt;/a&gt; hechas con dibujitos. También podéis ver &lt;a href=&quot;https://goo.gl/photos/A31X4868VKaCPQ8o9&quot; &gt;el trabajo de &lt;a href=&quot;https://twitter.com/oyabun?lang=en&quot; &gt;Javier (@oyabun)&lt;/a&gt; haciendo el Live recording&lt;/a&gt; del evento.
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Comienza &lt;a href=&quot;http://twitter.com/JaviSantana&quot; &gt;Javi Santana&lt;/a&gt;, CTO de &lt;a href=&quot;https://twitter.com/CARTO&quot; &gt;Carto&lt;/a&gt;&lt;/strong&gt; con &quot;Crear software para empresacas que manejan pasta de verdad&quot;.
  &lt;br /&gt;
  La idea principal que transmite es que si quieres &quot;gallina&quot; hay que ir a por la empresa, a instalar &quot;on premise&quot;. El cloud, la solución SAAS tiene un rendimiento muy bajo. Luego tienes que montar un super-equipo: Soluciones (Ninjas), Sales, Soporte (aka psicólogos). Refuerza algo que ya sabemos, que no hay que parar de investigar, si paras te mueres. Y termina con un mensaje, que &lt;strong&gt;el dinero mola, pero divertirse más.&lt;/strong&gt;
  &lt;br /&gt;
  Me gustó mucho, divertida, bien estructurada y conceptos claros.
&lt;/p&gt;

&lt;p&gt;
  &lt;img src=&quot;/assets/tarugo_IMG_20160916_102724-COLLAGE.jpg&quot; alt=&quot;Quest y regalinos&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;
  A continuación le toca a&lt;strong&gt; &lt;a href=&quot;https://twitter.com/jorge__galindo&quot; &gt;Jorge Galindo&lt;/a&gt;, Product Manager de &lt;a href=&quot;https://twitter.com/47deg&quot; &gt;47 Degrees&lt;/a&gt;,&lt;/strong&gt; una empresa que hace software para todo el mundo desde sus oficinas al lado de la Peña Camarón, en Puerto de Santa María, Cádiz, con un par. Su charla se tituló &quot;Emprender en provincias&quot;.
  &lt;br /&gt;
  Nos contó la historia de cómo llego &lt;a href=&quot;http://www.47deg.com/&quot;&gt;47 Degrees&lt;/a&gt; (latitud de Seattle) a Cádiz. Como pasó la empresa por lo estados de &quot;mundo de piruleta&quot;, &quot;hecatombe mundial&quot; y a quedarse sin pasta. Desde Cádiz se tuvo que reinventar empezando en corto, consiguió llegar a empresas de Madrid tirando de networking y les fue muy bien (por aquí pasó muy rápido, me hubiese gustado saber un poco más de este éxito). Pero entraron en un bucle de mucho curro y poca pasta que les obligó a fijar un punto de no retorno en el tiempo en el que buscarían otra cosa.
  &lt;br /&gt;
  Estando &lt;a href=&quot;https://twitter.com/raulraja&quot; &gt;Raúl Raja&lt;/a&gt; de vacaciones en Cartagena, leyó un artículo sobre Scala, llamó inmediatamente a Jorge para decirle que &lt;strong&gt;tenían que cambiar a Scala ya.&lt;/strong&gt; Y él le respondió: &lt;strong&gt;&quot;¡Del tirón!... ¿Cómo dices que se escribe?&quot;&lt;/strong&gt;. Aparte de la broma encontraron un nicho en la programación funcional que a base de investigar, mucho open source y atraer talento, les salvó el c... ¡Hicieron hasta un framework!
  &lt;br /&gt;
  ¿Qué cambiaría Jorge? Detalles, porque estás donde estás gracias a todas las experiencias. La pregunta que te tienes que hacer es si te gusta lo que eres y lo que estás haciendo.
&lt;/p&gt;

&lt;p&gt;
  Alguna idea: Todos los viernes mandan un correo a todo el mundo con información de en qué proyectos están y a menudo organizan actividades para todo el mundo.
  &lt;br /&gt;
  Les preocupa crecer por encima de 30, por si se pierde la &quot;magia&quot; (palabras literales), tema que me suena bastante.
  &lt;br /&gt;
  Charla muy potente, con buen ritmo. Quizás en la historia hay algún hueco que creo que se podría profundizar porque daría claves de cómo emprender desde fuera de Madrid, algo muy interesante para Codesai, sin duda.
&lt;/p&gt; 

&lt;p&gt;
  Antes del café una minicharla de IBM, en la que muestra la arquitectura de Cloud e IoT que hay detrás de mover un BB-8. Un toque geek molón rápido y a la yugular.
&lt;/p&gt;


&lt;img src=&quot;/assets/tarugo_IMG_20160916_100443-COLLAGE.jpg&quot; alt=&quot;Ponentes de la mañana&quot;/&gt;

&lt;p&gt;
  Después del café empieza &lt;a href=&quot;https://twitter.com/subidubi&quot; &gt;Jimena Catalina&lt;/a&gt;, con la charla &quot;Sácale provecho a tu diseñador&quot; (aunque en el programa era &quot;La culpa SIEMPRE es del diseñador&quot;). &lt;strong&gt;Jimena es Diseñadora visual freelance y tiene proyectos propios&lt;/strong&gt; como &lt;a href=&quot;https://twitter.com/derechupete&quot; &gt;Recetas de Rechupete&lt;/a&gt;. Me gustó escuchar a alguien más pegado al proceso de desarrollo que veo día a día.
  &lt;br /&gt;
  Nos explica que es fundamental que el diseñador entienda el proceso de negocio. Hay que trabajar muy cerca del equipo, porque no sólo es diseñarlo, es colaborar en lo que luego hacen con él.&lt;br /&gt;
  Destaca la importancia de un buen feedback, e intentar hablar del concreto, o qué se quiere conseguir, no de emociones.
  &lt;br /&gt;
  &lt;strong&gt; La mejor frase: &quot;Diseño NO es arte, no expresamos nuestras emociones. Somos artesanos al servicio, resolvemos necesidades&quot;&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  El toque de inversor potente vino a cargo de&lt;strong&gt; &lt;a href=&quot;https://twitter.com/jjmata&quot; &gt;Juanjo Mata&lt;/a&gt;. Español en los USA desde hace 25 años&lt;/strong&gt; con un acento para pronunciar el inglés que cuando lo oyes piensas: &quot;A este seguro que le entienden&quot;. David dice que es gallego, pero Juanjo mencionaba mucho a Toledo, no se porqué. En su twitter dice que es COO en Teambox.
  &lt;br /&gt;
  &quot;Si quieres vender necesitas un VP de Ventas&quot; y nos mostró una tabla de sueldos mareantes, todos con seis cifras. Comentó que en USA dan dinero por un 5% y te dejan trabajar y que en España siempre quieren influenciar en el negocio. Y expresó con impotencia que es muy difícil montar allí un equipo tecnológico estable, hay tanta oferta que se van a los dos días, lo que es un problema para conseguir ritmo.
  &lt;br /&gt;
  Fue una charla muy técnica, llena de siglas que no recuerdo y&lt;strong&gt; me enteré de muy poco, cosa que me hizo preguntarle: &quot;Como técnico que ayuda a Startups, ¿debería aprender más de inversión, en vez del siguiente framework?&quot;.&lt;/strong&gt; Su respuesta fue que solamente si quieres, aunque alguien tiene que saber de todo esto en la empresa.
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Ya oliendo el pulpo vino Molpe&lt;/strong&gt; (&lt;a href=&quot;https://twitter.com/molpe&quot; &gt;Alberto Molpeceres&lt;/a&gt;), que se ha especializado en que tu negocio pueda cobrar online, con su charla que en la agenda venía como &quot;Lo que diga Molpe&quot; y que él renombró&lt;strong&gt; &quot;Family Business&quot;.&lt;/strong&gt;
  &lt;br /&gt;
  &lt;strong&gt; Nos dejó a todos destrozados.&lt;/strong&gt; &lt;strong&gt;Una reflexión muy profunda de lo que significa (¡y lo que cuesta!) conciliar de verdad.&lt;/strong&gt;
  &lt;br /&gt;
  Cinco puntos:
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Distingue trabajo de hogar, que no te vean todo el día al ordenador.&lt;/li&gt;
  &lt;li&gt;Agenda compartida, respeta los huecos comunes, no pongas la empresa como excusa.&lt;/li&gt;
  &lt;li&gt;Las distancias importan.&lt;/li&gt;
  &lt;li&gt;Todos o ninguno, intenta que los eventos sean un viaje familiar.&lt;/li&gt;
  &lt;li&gt;Todo el mundo juega un rol. Involucra a todo el mundo en tu trabajo, en tus éxitos, en tus preocupaciones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
  El turno de preguntas &lt;strong&gt;convirtió la sala en una terapia de padres y madres&lt;/strong&gt; expresando sus problemas en el día a día en un nuevo escenario para muchos.
  &lt;br /&gt;
  No se si fue la mejor charla, pero sí la que más voy a recordar. Por lo inesperado del tema y lo bien tratado. Me llevo un montón de ideas para implementar en casa.
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;La comida tremenda.&lt;/strong&gt; La cantidad de pulpo, empanada, tortilla que me pude comer, sólo se queda pequeña comparada con la que desearía haber comido. Muy buen lugar, en un solar al lado del Campus, y muy buen ambiente para seguir saludando a los que todavía no habíamos podido.
&lt;/p&gt;

&lt;img src=&quot;/assets/29727990461_4f2a70fa63_z_d.jpg&quot; alt=&quot;Zona de la comida&quot; /&gt;

&lt;p&gt;
  Después de comer &lt;strong&gt;&lt;a href=&quot;https://twitter.com/cuquiesp&quot; &gt;Inés Luna&lt;/a&gt;, experta en atención al cliente&lt;/strong&gt; con la charla &quot;Usuarios, clientes y animales ¿Son todos iguales?&quot;
  &lt;br /&gt;
  Se centró en lo importante que es tener un buen equipo de soporte, que además esté muy en contacto con producto, tanto para saber cuándo salen las siguientes funcionalidades, cuando se resolverán ciertos errores o para dar ideas.
&lt;/p&gt;

&lt;p&gt;
  A continuación &lt;strong&gt;&lt;a href=&quot;https://twitter.com/diegomarino&quot; &gt;Diego Mariño&lt;/a&gt; con &quot;Así crearía Ducksboard en 2016&quot;. Diego fue fundador de &lt;a href=&quot;https://twitter.com/ducksboard&quot; &gt;Ducksboard&lt;/a&gt;, que fue adquirida por &lt;a href=&quot;https://twitter.com/newrelic&quot; &gt;New Relic&lt;/a&gt;,&lt;/strong&gt; de la que ahora es Principal Product Manager.
  &lt;br /&gt;
  Diego charló con el público más que una presentación. Habló de sus experiencias en Ducksboard y en USA. &lt;strong&gt;Buen ambiente vespertino.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Y para terminar subió al escenario&lt;strong&gt; &lt;a href=&quot;https://twitter.com/jemonleon&quot; &gt;Jesús Monleón&lt;/a&gt; &lt;/strong&gt;para hablar de &quot;Cómo montar un equipo comercial para salir a vender con el cuchillo entre los dientes&quot;. Jesús es inversor en &lt;a href=&quot;https://t.co/shejETNbes&quot; &gt;SeedRocket&lt;/a&gt; y fundador de &lt;a href=&quot;https://t.co/DWBQz8N6iw&quot; &gt;Offerum&lt;/a&gt; entre otras, &lt;strong&gt;siempre como responsable del equipo comercial.&lt;/strong&gt;
  &lt;br /&gt;
  Jesús nos llevó a sus inicios en eMagister con unas historias desternillantes sobre cómo se consigue vender algo.&lt;strong&gt; Entre mucho humor negro nos contó con detalle las interioridades de un equipo comercial.&lt;/strong&gt;
  &lt;br /&gt;
  Una charla muy personal y a veces dura que puso buen broche a las ponencias del día.
&lt;/p&gt;

&lt;img src=&quot;/assets/tarugo_29707537531_78fb517ee4_o-COLLAGE.jpg&quot; alt=&quot;Ponentes de la tarde&quot;/&gt;

&lt;p&gt;
  Y después del zumo terminamos con la &lt;strong&gt;Mesa Redonda de Medios Digitales&lt;/strong&gt;: &quot;la vida más allá de la publicidad y el CPM&quot;
  &lt;br /&gt;
  Conversación claramente para iniciados en el mundo del contenido y lo que significa ganar dinero con gente que viene a verte sin tener que cobrarles. En general estaban bastante alineados.
&lt;/p&gt;

&lt;h3&gt;Despedida&lt;/h3&gt;

&lt;p&gt;
  ¡Y va terminando el evento!
  &lt;br /&gt;
  Bonilla se sube a la palestra y nos cuenta los datos internos económicos de la Tarugoconf. El resultado sale positivo, pero nos aclara que es porque no ha tenido que pagar por varias cosas: como la sala (gracias a Campus Madrid), la web del evento (gracias a Space Nomads) y algo tan increíble como &lt;strong&gt;los vuelos de Juanjo Mata y Diego Mariño desde EEUU, ¡que se los pagaron ellos mismos!&lt;/strong&gt; Así que si contase con todos esos gastos el evento perdería mucho dinero.
&lt;/p&gt;
&lt;p&gt;
  A continuación da las gracias especialmente a &lt;a href=&quot;https://twitter.com/candelamd&quot; &gt;Candela&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/ydarias&quot; &gt;Yerai&lt;/a&gt; y &lt;a href=&quot;&amp;quot;https://twitter.com/jerolba&quot; &gt;Jero&lt;/a&gt;.
&lt;/p&gt;

&lt;img src=&quot;/assets/tarugo_IMG_20160916_194224.jpg&quot; alt=&quot;David dando las gracias al final&quot; /&gt;

&lt;p&gt;
  Nos comparte la certeza de que los eventos &quot;de autor&quot; son el futuro: Línea editorial, Experiencia, Networking y conseguir Leads valiosos, por encima de un CFP genérico y hacer branding personal.
&lt;/p&gt;

&lt;p&gt;
  Sobre si habrá Tarugoconf 2017, dice ahora mismo no le apetece,  pero que sabe que alguien pronunciará las tres palabras mágicas... así que se despidió &lt;strong&gt;&quot;¡Hasta el año que viene!&quot;.&lt;/strong&gt;
&lt;/p&gt;

&lt;h3&gt;Bola extra&lt;/h3&gt;

&lt;p&gt;
  &lt;a href=&quot;https://twitter.com/oyabun&quot; &gt;Javier Alonso (@oyabun)&lt;/a&gt; hizo un trabajo magistral, haciendo el &apos;Graphic Recording&apos; de todo el evento. Impresionó a todo el mundo. ¡Gracias y Enhorabuena!
&lt;/p&gt;

&lt;img class=&quot;alignnone&quot; src=&quot;/assets/graphicrecording.png&quot; alt=&quot;graphicrecording&quot; /&gt;

&lt;h3&gt;Feedback&lt;/h3&gt;

&lt;p&gt;
  Me acaba de llegar un correo en el que David nos pide feedback, lo dejo por aquí también:
&lt;/p&gt;
&lt;p&gt;
  Para repetir:
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tiempo para preguntas. 30 minutos de charla y 15 de preguntas.&lt;/li&gt;
  &lt;li&gt;El buen ambiente entre los asistentes, cada charla fantástica.&lt;/li&gt;
  &lt;li&gt;La tortilla caliente y poco cuajada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  Para mejorar en la siguiente:
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Un pequeño break entre charlas. Cinco minutos para despejar la mente.&lt;/li&gt;
  &lt;li&gt;La promesa de salir del evento con 10 contactos hiper-curated creo que no se cumplió. Seguro que no lo di todo conociendo gente, pero creo que si uno de los objetivos era ese habría que intentar alguna idea más para el año que viene.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;En resumen&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Muy potente, mucha energía, un ambiente espectacular&lt;/strong&gt; donde podías encontrar a un montón de compañeros y a los que no conocías sabías que iban a ser igual de interesantes; un conjunto de ponentes muy cuidado, con una presentación robusta  y &lt;strong&gt;con mensajes e ideas claras.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Una gran oportunidad para poder aprender de gente que se ha pegado muy duro y con ideas para llevar para aplicar desde ya.
&lt;/p&gt;

&lt;img src=&quot;/assets/llegada.png&quot; alt=&quot;llegada&quot; /&gt;

&lt;h3&gt;Fotos&lt;/h3&gt;
&lt;p&gt;
  &lt;a href=&quot;https://goo.gl/photos/A31X4868VKaCPQ8o9&quot; &gt;Live Sketching de Javier (@oyabun)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href=&quot;https://goo.gl/photos/Z1e53MuCXuv3cshT6&quot; &gt;Mis notas #sketchnoting&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href=&quot;https://bit.ly/tarugopics16&quot; &gt;Fotos oficiales de la Tarugoconf&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href=&quot;https://goo.gl/photos/KmgmH1qtYUBaBNmP9&quot; &gt;Mis fotos&lt;/a&gt;
&lt;/p&gt;
</description>
          <pubDate>2016-09-23T08:05:17+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/09/estuvimos-en-la-tarugoconf</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/09/estuvimos-en-la-tarugoconf</guid>
        </item>
      
    
      
        <item>
          <title>Recorriendo poco a poco el libro &quot;Understanding the 4 rules of simple design&quot;</title>
          <description>&lt;h1 id=&quot;kata-del-juego-de-la-vida-de-conway&quot;&gt;Kata del Juego de la Vida de Conway&lt;/h1&gt;

&lt;p&gt;En mis primeras semanas en &lt;a href=&quot;http://www.codesai.com&quot;&gt;Codesai&lt;/a&gt; he hecho la kata del &lt;a href=&quot;https://es.wikipedia.org/wiki/Juego_de_la_vida&quot;&gt;Juego de la Vida de Conway&lt;/a&gt; como parte de mi formación para empaparme de la cultura y valores de la empresa.&lt;/p&gt;

&lt;p&gt;La hice dos veces: la primera ha sido &lt;a href=&quot;https://github.com/adelatorrefoss/kata-tdd-game-of-life-inside-out-js&quot;&gt;TDD inside-out en Javascript&lt;/a&gt; con Karma, Mocha y Chai, y la segunda &lt;a href=&quot;https://github.com/adelatorrefoss/kata-game-of-life-groovy-outside-in&quot;&gt;TDD outside-in con Groovy&lt;/a&gt; y Spock. Dejo aquí mis enlaces al github donde se ve en cada commit qué decisiones he ido tomando siguiendo el ciclo: ROJO -&amp;gt; VERDE -&amp;gt; REFACTOR.&lt;/p&gt;

&lt;p&gt;Para ver una buena explicación de las diferencias de hacer TDD inside-out e outside-in, podéis leer este post: &lt;a href=&quot;https://www.adictosaltrabajo.com/tutoriales/tdd-outside-in-vs-inside-out/&quot;&gt;TDD: Outside-In vs Inside-Out&lt;/a&gt; en el fantástico &lt;a href=&quot;https://www.adictosaltrabajo.com/&quot;&gt;blog de Adictos al Trabajo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Después de hacer estas dos katas, he leído el libro &lt;a href=&quot;https://www.goodreads.com/book/show/21841698-understanding-the-four-rules-of-simple-design&quot;&gt;“Understanding the 4 rules of simple design”&lt;/a&gt; y he comparado mis decisiones.&lt;/p&gt;

&lt;p&gt;Lo que viene a continuación no es un resumen, son comentarios de lo que más me ha llamado la atención, así que te recomiendo leer el libro antes de seguir. Es corto, en un día lo tienes hecho.&lt;/p&gt;

&lt;h1 id=&quot;resumen-y-comentarios-del-libro-understanding-the-4-rules-of-simple-design&quot;&gt;Resumen y comentarios del libro “Understanding the 4 rules of simple design”&lt;/h1&gt;

&lt;p&gt;El libro empieza muy fuerte, con los prólogos de Kent Beck y J. B. Rainsberger de los que se sacan auténticas perlas:&lt;/p&gt;

&lt;h2 id=&quot;foreword-from-kent-beck&quot;&gt;Foreword from Kent Beck&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Is wrong “Design for the future. Change is expensive. Make it cheap by anticipating it.”&lt;/em&gt;
This looked like a positive feedback loop to me: more speculation -&amp;gt; worse design -&amp;gt; more speculation.&lt;/p&gt;

  &lt;p&gt;The good news about disastrous positive feedback loops is that you can generally drive them backwards.&lt;/p&gt;

  &lt;p&gt;I first experimented by ignoring any changes that seemed like they would happen longer than six month in the future. My designs were simpler, I started making progress sooner, and I stressed less about the unknowable future. I shortened the time horizon to three months. Much better.&lt;/p&gt;

  &lt;p&gt;One month. More. A week. A day. Oh, hell, what happens if I don’t add any design elements&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es muy gráfico cómo relata una especie de evolución de su pensamiento sobre qué pasaría si no adelantamos nada de supuestos futuros.&lt;/p&gt;

&lt;p&gt;Buceando un poco desde el enlace que da en el prólogo, llegué a un &lt;a href=&quot;http://martinfowler.com/bliki/BeckDesignRules.html&quot;&gt;artículo de Martin Fowler&lt;/a&gt; sobre estas reglas de diseño donde pone la siguiente cita de Kent Beck:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;At the time there was a lot of “design is subjective”, “design is a matter of taste” bullshit going around. I disagreed. There are better and worse designs. These criteria aren’t perfect, but they serve to sort out some of the obvious crap and (importantly) you can evaluate them right now.&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;The real criteria for quality of design, “minimizes cost (including the cost of delay) and maximizes benefit over the lifetime of the software,” can only be evaluated post hoc, and even then any evaluation will be subject to a large bag full of cognitive biases. The four rules are generally predictive.&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;– Kent Beck&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Creo que define muy bien lo que significan las buenas prácticas: &lt;em&gt;Estos criterios no son perfectos, pero sirven para detectar algo de la basura más obvia y (lo más importante) puedes evaluarlo inmediatamente.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;En un entorno de trabajo donde cualquier decisión es cuestionable, tener reglas básicas para distinguir el ‘crap-code’ ayuda mucho a las conversaciones dentro del equipo&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;foreword-from-j-b-reinsberger&quot;&gt;Foreword from J. B. Reinsberger&lt;/h2&gt;

&lt;p&gt;El siguiente prólogo está realmente bien. Pues ayuda a profundizar y hacerte una idea de las conversaciones que puede haber detrás de algo aparentemente tan sencillo como las cuatro reglas.&lt;/p&gt;

&lt;p&gt;Destaco como antes, no textos del prólogo, sino de los posts relacionados de JB. Son mencionados en numerosas ocasiones por todos los autores vistos hasta ahora y se recomiendan incluso por Corey Haines en el propio libro.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;http://blog.jbrains.ca/permalink/the-four-elements-of-simple-design&quot;&gt;The four elements of simple design&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;When I find fifteen lines of duplicate code, I start by extracting them to a new method, and since I probably don’t yet know what those lines of code do yet, I name the new method foo(). After around 15 minutes of working in the same area, I begin to understand what this method does, so I give it an accurate name, such as computeCost().&lt;/p&gt;

  &lt;p&gt;[…]&lt;/p&gt;

  &lt;p&gt;That leaves me with two key elements of simple design: remove duplication and fix bad names. When I remove duplication, I tend to see an appropriate structure emerge, and when I fix bad names, I tend to see responsibilities slide into appropriate parts of the design.&lt;/p&gt;

  &lt;p&gt;[…]&lt;/p&gt;

  &lt;p&gt;I claim that developing strong skills of detecting duplication, removing duplication, identifying naming problems, and fixing naming problems equates to learning everything ever written about object-oriented design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Este post es &lt;strong&gt;oro puro&lt;/strong&gt;, el primer párrafo me encanta, pues dar nombres a métodos o clases, es la tarea más difícil del desarrollo. Aquí da una pista muy buena.&lt;/p&gt;

&lt;p&gt;El siguiente post relacionado de JB, es la continuación del anterior, e intenta cerrar la ‘guerra’ abierta sobre el orden de importancia de las cuatro reglas.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;http://blog.thecodewhisperer.com/permalink/putting-an-age-old-battle-to-rest/&quot;&gt;Putting an age old battle to rest&lt;/a&gt;
I don’t think it matters whether you focus first on removing duplication or on revealing intent/increasing clarity, because these two guidelines very quickly form a rapid, tight feedback cycle. By the time the guidelines guide you to any useful results, you’ll have probably used them both. Therefore, order the rules however you like, because you’ll get to the same place either way.&lt;/p&gt;

  &lt;p&gt;…&lt;/p&gt;

  &lt;p&gt;When we remove duplication, we create buckets; when we improve names, we create more cohesive, more easily-abstracted buckets.&lt;/p&gt;

  &lt;p&gt;…&lt;/p&gt;

  &lt;p&gt;Now, I think of them as a single guideline: remove duplication and improve names in small cycles. When I do this, I produce a higher proportion of  well-factored code compared to all the code I write.&lt;/p&gt;

  &lt;p&gt;…&lt;/p&gt;

  &lt;p&gt;Removing duplication and improving names helps me reduce the liability (cost) of the code that I write. Together, they help me reduce both the total cost and the volatility of the cost of the features I deliver.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En estos tres párrafos habla de tres temas muy potentes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Cerrar la guerra sobre el orden&lt;/li&gt;
  &lt;li&gt;Cohesión&lt;/li&gt;
  &lt;li&gt;Coste&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;introduction-this-book&quot;&gt;Introduction: This book&lt;/h2&gt;

&lt;p&gt;Me encanta esta introducción. Habla con más claridad de lo que hemos visto hasta ahora: cómo las cuatro reglas se retroalimentan, incidiendo en lo comentado por JB.&lt;/p&gt;

&lt;p&gt;Recalca como Kent Beck que no ve que haya diseños buenos y malos, e incluso que puede haber varios buenos diseños. A partir de ahí, comparándolos se podría llegar a un consenso de las ideas fundamentales de por qué un diseño es “mejor” que otro.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If we can look at things from a comparison point of view, perhaps we can find some fundamental ideas about “better”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Termina formulando las dos constantes en el desarrollo de software, acompañado de un tweet de &lt;a href=&quot;https://twitter.com/sandimetz&quot;&gt;Sandi Metz&lt;/a&gt;: &lt;strong&gt;“Habrá cambios pero no sabemos qué es lo que va a cambiar”&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;A continuación entramos en materia del libro con diferentes ejemplos divididos en capítulos (respeto los títulos en inglés), como si fuéramos construyendo desde cero el Juego de la Vida.&lt;/p&gt;

&lt;h3 id=&quot;test-names-should-influence-objects-api&quot;&gt;Test Names Should Influence Object’s API&lt;/h3&gt;

&lt;pre&gt;// Test: Check world is empty
// NO
world.cell_alive_at(1,1)?
// YES
world.empty?&lt;/pre&gt;
&lt;p&gt;Hay que usar nombres de test de hablen de negocio, y construir un API apropiada. Si usamos nombres de test orientados a datos, corremos el riesgo de construir un código que expone información que no es responsabilidad de la clase. &lt;/p&gt;
&lt;h3 id=&quot;duplication-of-knowledge-about-topology&quot;&gt;Duplication of Knowledge about Topology&lt;/h3&gt;
&lt;pre&gt;class LivingCell
    attr_reader :location
end class
&lt;/pre&gt;

&lt;p&gt;Aquí, Corey Hanes propone poner la localización dentro de la celdas, para no duplicar el conocimiento acerca de la topología del sistema, como en el código visto antes.&lt;/p&gt;

&lt;p&gt;Pensé en hacer esto, pero tal como estaba resolviendo el problema, no podía mover o quitar el conocimiento de la ubicación de las células fuera de la clase Grid, que está un nivel hacia afuera: lo necesitaba para recorrer la malla y calcular la siguiente iteración y para calcular el número de vecinos.&lt;/p&gt;

&lt;p&gt;Como experimento para esta kata, la estructura de datos en la que almacené las células de la malla, una estructura de dos dimensiones, fue en un tipo List, unidimensional. Y para consumirlo, desarrollé una especie de Iterable y el acceso a un elemento concreto con paginación.&lt;/p&gt;

&lt;p&gt;Así, el primero de los problemas que comento lo tenía resuelto, no se iba a recorrer la malla.&lt;/p&gt;

&lt;p&gt;El segundo problema, el de calcular el número de vecinos es el que no supe cómo resolverlo. ¿Cómo podía acceder a los vecinos de un elemento, si la posición que ocupan la tiene solo los elementos? ¿Cómo accedo a un elemento concreto de la malla?&lt;/p&gt;

&lt;p&gt;Después de terminar la kata, se me ocurrió una solución a esto. Podría haber usado métodos como .filter() sobre el List, para buscar elementos. No es muy eficiente, pero consigue lo que se quiere, abstraes la localización del Grid y se lo pasas a las células, lo probaré para la próxima.&lt;/p&gt;

&lt;h3 id=&quot;behavior-attractors&quot;&gt;Behavior Attractors&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Whenever we have a new method — a new behavior — an important question is “where do we put it?” What type does this belong to?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Siempre que tenemos un nuevo comportamiento la pregunta es dónde lo ponemos.&lt;/p&gt;

&lt;p&gt;En el libro recomienda no pararse demasiado a analizar dónde ubicarlo. Buscar rápidamente un sitio. Si nos encaja, perfecto; pero si no, tenemos que moverlo. Además cuanto antes para que luego con el uso no sea más difícil.&lt;/p&gt;

&lt;pre&gt;// Where do we put neighbors?
// Location seems perfect.
class Location
     attr_reader :x, :y
     &lt;strong&gt;def neighbors&lt;/strong&gt;
         # calculate a list of locations
         # that are considered neighbors
      end
 end&lt;/pre&gt;

&lt;p&gt;Destaca que a través del proceso de eliminar la duplicación de conocimiento de manera agresiva es como conseguimos clases que atraigan comportamientos. Y como corolario, si intentamos eliminar esa duplicidad y no encontramos dónde colocarlo es que nos falta alguna abstracción.&lt;/p&gt;

&lt;p&gt;En el ejemplo de código, me llamó mucho la atención poner los neighbors en Location. Porque eso significa que es un dato que se guarda, no un dato calculado al momento del tick. Interesante para explorar.&lt;/p&gt;

&lt;h3 id=&quot;testing-state-vs-testing-behavior&quot;&gt;Testing State vs Testing Behavior&lt;/h3&gt;

&lt;p&gt;En este apartado habla que hay que testear el comportamiento y no el estado, y pone como ejemplo que lo primero que comprueba en la kata es:&lt;/p&gt;

&lt;pre&gt;world.empty?&lt;/pre&gt;

&lt;p&gt;Yo lo que pensé que era el primer comportamiento era algo como:&lt;/p&gt;

&lt;pre&gt;world.stable?&lt;/pre&gt;
&lt;p&gt;Es decir: “¿Es el sistema estable? ¿Hay que hacer una siguiente iteración? ¿Cuál es la condición de parada?”. Comentándolo con los compañeros, parece que afronté el problema desde demasiado afuera. Outside-in no quiere decir literalmente: “Desde la capa más exterior, hacia dentro”.&lt;/p&gt;

&lt;h3 id=&quot;dont-have-tests-depend-on-previous-tests&quot;&gt;Don’t Have Tests Depend on Previous Tests&lt;/h3&gt;

&lt;pre&gt;def test_an_empty_world_stays_empty_after_a_tick
     world = World.new
     next_world = world.tick
     assert_true next_world.empty?
 end&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Rather new world is empty, let’s explicitly ask for an empty world.&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;def test_an_empty_world_stays_empty_after_a_tick
     world = World.empty
     next_world = world.tick
     assert_true next_world.empty?
 end&lt;/pre&gt;

&lt;p&gt;Si cambiamos el constructor base y devuelve otra cosa que un mundo vacío, el primer test continuará pasando. Para evitar esto, quien invoque al objeto no debería usar el constructor base con la confianza que vendrá con un estado específico, y menos en la preparación del test, debería usar un ‘constructor’, un ‘builder’, para crear un objeto con un estado concreto y válido.&lt;/p&gt;

&lt;p&gt;Esto me parece simplemente genial. Dejar de confiar en los constructores y crear builders que te den el objeto en el estado deseado. Es un problema que me encuentro de manera recurrente, no confío en los datos que tengo al preparar un test.&lt;/p&gt;

&lt;h3 id=&quot;breaking-abstraction-level&quot;&gt;Breaking Abstraction Level&lt;/h3&gt;

&lt;pre&gt;def test_world_is_not_empty_after_adding_a_cell
     world = World.empty
     world.set_living_at&lt;b&gt;(Location.new(1,1))&lt;/b&gt;
     assert_false &lt;b&gt;world.empty?&lt;/b&gt;
end
&lt;/pre&gt;

&lt;p&gt;Este tests está acoplado a una capa de abstracción que no es la suya, por lo que si se cambia el sistema de coordenadas a tres dimensiones, por ejemplo, fallarán tests que no tienen nada que ver.&lt;/p&gt;

&lt;p&gt;El libro recomienda en este caso hacer un doble de test que abstraiga de ese detalle. Otra opción puede ser usar un helper que de cree ese objeto de coordenadas y así solo está definido en un sitio.&lt;/p&gt;

&lt;pre&gt;def test_world_is_not_empty_after_adding_a_cell
    world = World.empty
    world.set_living_at(Object.new)
    assert_false world.empty?
end
&lt;/pre&gt;

&lt;p&gt;Este tipo de problemas nos hacen ver todos los puntos de contacto que tienen nuestros objetos con los demás.&lt;/p&gt;

&lt;h3 id=&quot;naive-duplication&quot;&gt;Naive Duplication&lt;/h3&gt;

&lt;p&gt;Muy interesante esta sección en la que veremos las diferencias entre duplicidad de código y duplicidad de lógica de negocio.&lt;/p&gt;

&lt;p&gt;Vamos a observar las condiciones para que una célula viva en la siguiente generación:&lt;/p&gt;

&lt;pre&gt;class Cell
    # ...
    def alive_in_next_generation?
        if alive
            number_of_neighbors == 2 ||
            number_of_neighbors == 3
        else
            number_of_neighbors == 3
        end
    end
end
&lt;/pre&gt;

&lt;p&gt;Podríamos refactorizar este código:&lt;/p&gt;

&lt;pre&gt;// An optimization of is_alive condition
class Cell
    # ...
    def alive_in_next_generation?
        (alive &amp;amp;&amp;amp; number_of_neighbors == 2) ||
            number_of_neighbors == 3
    end
end
&lt;/pre&gt;

&lt;p&gt;Con este refactor de código recordamos una de las cuatro reglas: “El conocimiento se debe representar una y solamente una vez”.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Every piece of knowledge has one and only one representation.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mirando otra vez al código original podemos ver que esos 3s no significan lo mismo.&lt;/p&gt;

&lt;p&gt;Recomienda que una buena técnica para no caer en este error, sería nombrar de forma explícita los conceptos antes de refactorizar.&lt;/p&gt;

&lt;pre&gt;class Cell
    # ...
    def alive_in_next_generation?
        if alive
            stable_neighborhood?
        else
            genetically_fertile_neighborhood?
        end
    end
end&lt;/pre&gt;

&lt;p&gt;Así se ve mucho mejor y en caso de cambiar las condiciones de supervivencia, accedemos a reglas de negocio directamente.&lt;/p&gt;

&lt;p&gt;En mi código no hice refactor porque me di cuenta que no era el mismo conocimiento, pero no extraje a un método cada comportamiento, interesante apunte para la próxima.&lt;/p&gt;

&lt;h3 id=&quot;procedural-polymorphism&quot;&gt;Procedural Polymorphism&lt;/h3&gt;

&lt;p&gt;El if en el código del apartado anterior diferencia los casos comprobando el valor del estado:&lt;/p&gt;

&lt;pre&gt;if state == ALIVE
...
&lt;/pre&gt;

&lt;p&gt;En esta sección destaca que el uso de variables de estado es un indicio de que no se ha entendido el negocio. Interesante.&lt;/p&gt;

&lt;p&gt;¿Cómo resolvemos esto? Nos presenta el Polimorfismo, como una técnica que nos da la posibilidad de llamar a un único método y tener más de un posible comportamiento. Si usamos ifs para hacer estas diferencias le llama &lt;strong&gt;Procedural Polymorphism&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cuando vi esto me vino a la cabeza que una buena razón para no tener cuerpos ifs muy grandes o complejos es que se podría romper el Principio Open/Close. Deberían ser super-sencillos.&lt;/p&gt;

&lt;p&gt;Avanzando con el polimorfismo, la OO nos da su método preferido, el Polimorfismo basado en tipos.&lt;/p&gt;

&lt;p&gt;Así en nuestro ejemplo podemos coger el estado y trasladarlo a un par de tipos:&lt;/p&gt;

&lt;pre&gt;class LivingCell
    def alive_in_next_generation?
        # neighbor_count == 2 || neighbor_count == 3
        stable_neighborhood?
    end
end

class DeadCell
    def alive_in_next_generation?
        # neighbor_count == 3
        genetically_fertile_neighborhood?
    end
end
&lt;/pre&gt;

&lt;p&gt;¡Polimorfismo! ¡Me encanta! Me parece muy mágico y elegante.&lt;/p&gt;

&lt;p&gt;Pero Haines no lo deja ahí, no nos deja tranquilos en nuestra satisfacción. A continuación rompe el polimorfismo de este ejemplo cambiando de nombre a los métodos. ¿Por qué?&lt;/p&gt;

&lt;p&gt;La explicación que da, es que el polimorfismo hace abstracciones muy atractivas que podrían ocultar detalles del comportamiento real de cada subtipo, siendo incorrecto ese genérico que queremos atribuirle.&lt;/p&gt;

&lt;p&gt;Para darnos un ejemplo, se plantea la propia existencia de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeadCell&lt;/code&gt;, pues no tendría mucho sentido si el tamaño del Grid fuera infinito.&lt;/p&gt;

&lt;p&gt;Es muy fácil, sobre todo al principio, sacar abstracciones rápidamente y hacer una jerarquía de tipos. Pero si nos damos cuenta que es incorrecta deshacerla suele ser complicado.&lt;/p&gt;

&lt;h3 id=&quot;making-assumptions-about-usage&quot;&gt;Making Assumptions About Usage&lt;/h3&gt;

&lt;p&gt;La idea fundamental bajo la pregunta: “¿Necesitamos esta abstracción?” es: “El uso influencia la estructura”. Propone que hay que construir nuestra lógica de negocio y las abstracciones que usemos motivadas por el uso que hagamos.&lt;/p&gt;

&lt;h3 id=&quot;unwrapping-an-object&quot;&gt;Unwrapping an Object&lt;/h3&gt;

&lt;p&gt;Partiendo de este trozo de código que muestra una solución para contar los vecinos de una célula:&lt;/p&gt;

&lt;pre&gt;class Location
    attr_reader :x, :y
end

location1 = Location.new(1, 1)
location2 = Location.new(1, 2)

if location1.equals?(location2)
    # Do something interesting
end
&lt;/pre&gt;

&lt;p&gt;Para hacer ese “algo interesante” tenemos que saber si las dos posiciones son iguales. Y generalmente haríamos algo como esto:&lt;/p&gt;

&lt;pre&gt;class Location
    attr_reader :x, :y
    def equals?(other_location)
        self.x == other_location.x &amp;amp;&amp;amp;
        self.y == other_location.y
    end
end

location1.equals?(location2)
&lt;/pre&gt;

&lt;p&gt;¿Qué sucedería si aplicamos en la kata la restricción (muy potente) de “Nuestras funciones no pueden retornar valores”?&lt;/p&gt;

&lt;p&gt;Tendríamos que transformar este código para que cumpla el &lt;strong&gt;‘Tell, don’t ask’&lt;/strong&gt; y confiar en los objetos para que hagan un trabajo que generalmente haríamos nosotros.&lt;/p&gt;

&lt;p&gt;Para ello propone una solución muy interesante, el uso de lambdas: le decimos al &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.equals?&lt;/code&gt; lo que queremos que ejecute si se cumple la condición.&lt;/p&gt;

&lt;pre&gt;count_of_locations = 0
location1.equals?(location2, &lt;b&gt;-&amp;gt; { count_of_locations++ }&lt;/b&gt;)

class Location
    attr_reader :x, :y
    def equals?(other_location, &lt;b&gt;if_equal&lt;/b&gt;)
        other_location.equals_coordinate?(self.x, self.y, &lt;b&gt;if_equal&lt;/b&gt;)
        nil
    end

    def equals_coordinate?(other_x, other_y, &lt;b&gt;if_equal&lt;/b&gt;)
        if self.x == other_x &amp;amp;&amp;amp; self.y == other_y
            &lt;b&gt;if_equal.()&lt;/b&gt;
        end
            nil
    end
end
&lt;/pre&gt;

&lt;p&gt;Es de destacar que como no podemos retornar nada, hay que invocar a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;other_location&lt;/code&gt; con la lambda, para que lo ejecute.&lt;/p&gt;

&lt;p&gt;Me ha encantado encontrarme el uso de funciones anónimas en este ejemplo; creo que combinándolo con el apartado anterior de “Romper el nivel de abstracción” puede quedar un código con menos efectos laterales.&lt;/p&gt;

&lt;h3 id=&quot;inverted-composition-as-a-replacement-for-inheritance&quot;&gt;Inverted Composition as a Replacement for Inheritance&lt;/h3&gt;

&lt;p&gt;Volvemos al ejemplo anterior del polimorfismo:&lt;/p&gt;

&lt;pre&gt;// Let&apos;s create mother class
class Cell
&lt;b&gt;    attr_reader :location&lt;/b&gt;
end

class LivingCell &amp;lt; Cell
end

class DeadCell &amp;lt; Cell
end
&lt;/pre&gt;

&lt;p&gt;Esta extracción al crear el padre no introduce un nuevo concepto de dominio. La herencia es a menudo utilizada como una forma de “reusar” más que para eliminar duplicidades.&lt;/p&gt;

&lt;p&gt;Es un error común crear clases ‘base’ de este estilo, que pueden llegar a ser un contenedor de comportamientos muy poco relacionados.&lt;/p&gt;

&lt;p&gt;Si la herencia no es un solución, ¿qué otras opciones tenemos?&lt;/p&gt;

&lt;p&gt;En el ejemplo usa módulos de Ruby, y en otros lenguajes tendríamos Traits (Groovy) y en otros algo como los decoradores.&lt;/p&gt;

&lt;pre&gt;class LivingCell
    include HasLocation
end

class DeadCell
    include HasLocation
end
&lt;/pre&gt;

&lt;p&gt;Llegados a este punto, con la duplicidad medio resuelta, vemos que tenemos dos clases apuntando al mismo tipo, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(Living|Dead)Cell&lt;/code&gt; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Una técnica útil es &lt;strong&gt;Invertir la dependencia&lt;/strong&gt;, que la localización apunte a las células.&lt;/p&gt;

&lt;pre&gt;class Location
    attr_reader :x, :y
&lt;b&gt;    attr_reader :cell&lt;/b&gt;
end 

class LivingCell
    def stays_alive?(number_of_neighbors)
        number_of_neighbors == 2 ||
        number_of_neighbors == 3
    end 
end 

class DeadCell
    def comes_to_life?(number_of_neighbors)
        number_of_neighbors == 3
    end
end
&lt;/pre&gt;

&lt;p&gt;De esta manera, las clases que representan células están únicamente centradas en la información que les atañe, como las reglas sobre cómo evolucionan.&lt;/p&gt;

&lt;p&gt;También hemos extraído la topología de las reglas del juego, viendo que el tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt; tiene un rol de estructura, que une la malla con la célula.&lt;/p&gt;

&lt;p&gt;Comparando con mi código, la composición invertida es muy similar a la solución que había propuesto yo inicialmente en la kata: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Grid -&amp;gt; Position -&amp;gt; Info&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como ‘Rule of Thumb’ la dependencia de clases debe ir desde la que más cambia a la que menos cambia, desde la menos estable a la más estable, es decir, la dependencia la tiene que tener aquella que tiene más posibilidades de cambiar sus atributos.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h2&gt;

&lt;p&gt;Programar el Juego de la Vida de dos maneras diferentes y luego leerme este libro ha resultado ser un ejercicio muy intenso y productivo. ¡Y escribir este post, claro!&lt;/p&gt;

&lt;p&gt;Me llevo un buen montón de herramientas.&lt;/p&gt;

&lt;p&gt;A continuación voy a leerme el libro &lt;a href=&quot;https://www.goodreads.com/book/show/13507787-practical-object-oriented-design-in-ruby&quot;&gt;“Practical Object-Oriented Design in Ruby”&lt;/a&gt;, de Sandi Metz. Os iré contando!&lt;/p&gt;
</description>
          <pubDate>2016-09-14T09:16:31+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/09/recorriendo-poco-a-poco-el-libro-understanding-the-4-rules-of-simple-design</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/09/recorriendo-poco-a-poco-el-libro-understanding-the-4-rules-of-simple-design</guid>
        </item>
      
    
      
        <item>
          <title>Kata: object literal to query string</title>
          <description>&lt;p&gt;
  No long ago, we had to write a function that takes an object and returns a string to be sent as part of the query string in the request. This was because the communication mechanism was &lt;a href=&quot;https://en.wikipedia.org/wiki/JSONP&quot; &gt;JSONP&lt;/a&gt; that works via the GET method. The server was already expecting the specific format shown below and we didn&apos;t have access to the server in order to change it and accept just an URL-encoded JSON. The fun started when we realised that an object may be a tree structure with nested objects. We test-drove the solution and found it interesting as a code kata. This is the expected behavior of the function:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Suui/2dc92868812dbcec05d94daffa8d418a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  This is our implementation:
&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/Suui/e853998ca19d172c6398e4147e8ef2b2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
  Note that the object can&apos;t contain arrays neither functions.
&lt;/p&gt;

&lt;p&gt;
  Play with the code in &lt;a href=&quot;https://babeljs.io/repl/#?babili=false&amp;evaluate=true&amp;lineWrap=false&amp;presets=es2015%2Creact%2Cstage-2&amp;code=function%20objectToQueryString(obj)%7B%0A%20%20%20%20%20if%20(isNotConvertible(obj))%20return%20%22%22%3B%0A%20%0A%20%20%20%20%20let%20queryString%20%3D%20%22%22%3B%0A%20%20%20%20%20for%20(let%20propertyName%20in%20obj)%7B%0A%20%20%20%20%20%20%20%20%20let%20propertyValue%20%3D%20obj%5BpropertyName%5D%3B%0A%20%20%20%20%20%20%20%20%20if%20(isAnObject(propertyValue))%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20let%20convertedNestedProperties%20%3D%20objectToQueryString(propertyValue)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.split(&apos;%26&apos;)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20let%20surroundedProperties%20%3D%20surroundNestedWithBrackets(%0A%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20propertyName%2C%20%0A%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20convertedNestedProperties)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20queryString%20%2B%3D%20surroundedProperties.join(&apos;%26&apos;)%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20queryString%20%2B%3D%20%60%24%7BpropertyName%7D%3D%24%7BpropertyValue%7D%60%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20queryString%20%2B%3D%20&apos;%26&apos;%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%20return%20removeLastAmpersand(queryString)%3B%0A%20%7D%0A%20%0A%20function%20surroundNestedWithBrackets(propertyName%2C%20nestedProperties)%7B%0A%20%20%20%20%20let%20surrounded%20%3D%20%5B%5D%3B%0A%20%20%20%20%20for(let%20i%20%3D%200%3B%20i%20%3C%20nestedProperties.length%3B%20i%2B%2B)%7B%0A%20%20%20%20%20%20%20%20%20let%20nested%20%20%3D%20nestedProperties%5Bi%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nestedName%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nestedValue%3B%0A%20%20%20%20%20%20%20%20%20let%20isNestedObject%20%3D%20nested.indexOf(&apos;%5B&apos;)%20%3E%3D%200%3B%0A%20%20%20%20%20%20%20%20%20if%20(isNestedObject)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20nestedName%20%3D%20substringUntil(&apos;%5B&apos;%2C%20nested)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20nestedValue%20%3D%20substringFrom(&apos;%5B&apos;%2C%20nested)%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20nestedName%20%3D%20substringUntil(&apos;%3D&apos;%2C%20nested)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20nestedValue%20%3D%20substringFrom(&apos;%3D&apos;%2C%20nested)%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20surrounded.push(%60%24%7BpropertyName%7D%5B%24%7BnestedName%7D%5D%24%7BnestedValue%7D%60)%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%20return%20surrounded%3B%0A%20%7D%0A%20%0A%20function%20substringUntil(symbol%2C%20text)%7B%0A%20%20%20%20%20return%20text.substring(0%2C%20text.indexOf(symbol))%3B%0A%20%7D%0A%20%0A%20function%20substringFrom(symbol%2C%20text)%7B%0A%20%20%20%20%20return%20text.substring(text.indexOf(symbol))%3B%0A%20%7D%0A%20%0A%20function%20isNotConvertible(obj%20)%7B%0A%20%20%20%20%20return%20!obj%20%20%7C%7C%0A%20%20%20%20%20%20%20%20%20typeof(obj)%20!%3D%20&apos;object&apos;%20%7C%7C%0A%20%20%20%20%20%20%20%20%20JSON.stringify(obj)%20%3D%3D%22%7B%7D%22%3B%0A%20%7D%0A%20%0A%20function%20isAnObject(val)%7B%0A%20%20%20%20%20return%20typeof(val)%20%3D%3D%20&apos;object&apos;%3B%0A%20%7D%0A%20%0A%20function%20removeLastAmpersand(queryString)%7B%0A%20%20%20%20%20if%20(queryString.lastIndexOf(%22%26%22)%20%3D%3D%20queryString.length%20-1)%7B%0A%20%20%20%20%20%20%20%20%20return%20queryString.substring(0%2C%20queryString.length%20-1)%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%20return%20queryString%3B%0A%20%7D%0Aconsole.log(objectToQueryString(%7Ba%3A1%2C%20b%3A2%2C%20c%3A%7Bd%3A4%2C%20e%3A%7Bx%3A%7Bz%3A5%7D%2C%20h%3A7%7D%7D%7D))%3B%0A%0A%0A%0A&quot; &gt;the Babel Repl&lt;/a&gt;.
&lt;/p&gt;
</description>
          <pubDate>2016-09-07T20:29:20+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/09/kata-object-literal-to-query-string</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/09/kata-object-literal-to-query-string</guid>
        </item>
      
    
      
        <item>
          <title>Antonio de la Torre se une a Codesai</title>
          <description>&lt;figure&gt;
    &lt;img src=&quot;/assets/P1190246-1024x768.jpg&quot; alt=&quot;Foto de equipo&quot; /&gt; 
    &lt;figcaption&gt;Miguel, Antonio, Carlos, Jose - Tenerife, Julio 2016&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;
  Estamos de celebración, super &lt;a href=&quot;https://about.me/adelatorrefoss&quot; &gt;Antonio de la Torre&lt;/a&gt; forma parte del equipo Codesai desde esta misma semana. Antonio &lt;a href=&quot;https://adelatorrefoss.wordpress.com/2016/07/30/cierre-de-ciclo/&quot; &gt;ya había decidido&lt;/a&gt; que se volvía a su tierra (Oviedo) con la familia cuando nos encontramos en &lt;a href=&quot;http://jsday.es/#5724627624001536&quot; &gt;JSDayEs 2016&lt;/a&gt; y estuvimos charlando. Me contó sus planes y ví que nos podía encajar muy bien en Codesai, donde necesitabamos crecer en vista de la &lt;a href=&quot;/2016/06/nos-asociamos-con-kairos-ds&quot; &gt;alianza con Kairós&lt;/a&gt;. La actitud de Antonio nos gustó a todo el equipo, su madurez, su empatía y como no, su experiencia con métodos ágiles. Cualquiera que haya hablado un rato con Antonio sabe que tiene una mente abierta y predisposición para ayudar a los demás. Desde entonces nos pusimos a trabajar para alinearnos en el plano más técnico. Hicimos una kata de programación en remoto, Antonio se leyó algunos libros que le recomendamos, y encima nos &lt;a href=&quot;/2016/06/estuvimos-en-pamplona-software-craftsmanship-2016&quot; &gt;fuimos juntos al evento Software Craftsmanship de Pamplona&lt;/a&gt; (donde fuimos compañeros de habitación) y al &lt;a href=&quot;/2016/07/estuvimos-en-aos2k16&quot; &gt;AOS de Galicia&lt;/a&gt;. Tras los eventos, Antonio vino al curso de TDD que impartió Luis en Madrid y a la semana siguiente vino al que impartí yo en Tenerife. Así hicimos entrevista técnica y training, todo en uno, en un proceso que ha durado varios meses. Durante todos estos encuentros, absolutamente todos los miembros del equipo han podido conocer en persona a Antonio, pese a que estamos distribuidos en diferentes provincias. Estamos realmente contentos y nos sentimos afortunados de contar con Antonio en el equipo. Es una nueva etapa que nos hará crecer a todos.
&lt;/p&gt;

&lt;p&gt;
  El equipo Codesai ha crecido relativamente rápido pero sin buscarlo. Ahora el reto es mantenerlo y hacer más piña cada día. Hacer del equipo un instrumento que ayude a mejorar la industria del desarrollo de software y por qué no, tambien aportar nuestro granito de arena a la sociedad.
&lt;/p&gt;
</description>
          <pubDate>2016-08-23T10:17:27+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/08/antonio-de-la-torre-se-une-a-codesai</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/08/antonio-de-la-torre-se-une-a-codesai</guid>
        </item>
      
    
      
        <item>
          <title>Claves primarias: inmutabilidad y generación</title>
          <description>&lt;p&gt;
  Hace unos días &lt;a href=&quot;https://twitter.com/Pablyte/status/754056720666730500&quot; &gt;Pablo Iglesias&lt;/a&gt; &lt;a href=&quot;https://twitter.com/Pablyte/status/754056720666730500&quot; &gt;tuiteó&lt;/a&gt; una pregunta de Stack Exchange en la que hablaban sobre la inmutabilidad de las claves primarias. Se generó un debate bastante interesante en Twitter que se extendió más allá de la cuestión de la inmutabilidad. Este es un intento de recopilar y explicar algunos de los conceptos que se mencionaron durante ese debate.
&lt;/p&gt;

&lt;h1&gt;Claves primarias mutables o inmutables&lt;/h1&gt;

&lt;p&gt;
  Para el que ande un poco perdido con el concepto, básicamente se trata de determinar si la clave primaria de una entidad debería poder cambiar o no una vez establecida. Por ejemplo: si me registro en un servicio online y utilizan mi email como PK, si el servicio me da la opción de cambiar mi cuenta de correo, la PK es mutable. Esto significa que en todos los sitios en los que el servicio se esté persistiendo mi email como PK va a tener que actualizar el dato para constatar el cambio. Independientemente de que usemos o no foreign keys, esto es un foco de dolor, especialmente si utilizamos distintos mecanismos de persistencia de datos. Si además nuestro software cuenta con funcionalidades como con auditar los cambios o cualquier tipo de integración con sistemas externos como herramientas de CRM y similar, tener PKs mutables se puede convertir en algo imposible.
&lt;/p&gt;

&lt;p&gt;Parece que hubo un consenso generalizado respecto a que las PK deberían ser inmutables, así que no me voy a extender más en este punto.
&lt;/p&gt;

&lt;h1&gt;Claves subrogadas o naturales&lt;/h1&gt;

&lt;p&gt;
  Cuando usamos una clave natural, el valor de la clave está relacionado con los datos que identifica. Por ejemplo, si estamos identificando libros, el ISBN podría ser un candidato a PK. El número de bastidor para un coche, número de serie de un ordenador, la MAC de una tarjeta de red, el número de una factura, etc. En resumen, utilizamos un dato del negocio para identificar nuestras entidades al persistirlas.
&lt;/p&gt;

&lt;p&gt;
  Si, por otro lado, elegimos usar una clave subrogada, lo que estamos haciendo es generar un identificador único que no tiene nada que ver con los datos que identifica, pero se garantiza a nivel infraestructura que el dato es único.
&lt;/p&gt;

&lt;p&gt;Aunque siempre pongo un gran &quot;depende&quot; y no soy muy amigo de las afirmaciones absolutas, la realidad es que llevo años utilizando claves subrogadas porque la experiencia me ha demostrado que suele ser una mala idea utilizar datos del negocio. La razón es muy sencilla: el negocio cambia.
&lt;/p&gt;

&lt;p&gt;Ejemplos hay miles. Por tomar uno, &lt;a href=&quot;https://twitter.com/panicoenlaxbox&quot; &gt;Sergio León&lt;/a&gt; mencionaba los ISBN de los libros. Desarrollando un software para gestionar liberías podríamos pensar que el ISBN debería valernos, pero los libros muy viejos no tienen ISBN. Así que si de repente al librero le diese por dedicarse a vender libros antiguos de colección, tendríamos un problema importante. Ese tipo de situaciones se dan con mucha frecuencia y siempre cuando el desarrollo ya está bastante avanzado, que es cuando más daño hacen.
&lt;/p&gt;

&lt;p&gt;
  Como el ejemplo del ISBN hay muchos y debemos tener en cuenta el coste del cambio. Hay quién podría utilizar el argumento de que es un error pensar en el futuro y que usar una clave subrogada es una decisión prematura basada en anticiparse a un posible cambio de negocio que no sabemos si alguna vez va a suceder. En esas circunstancias suele ser un buen ejercicio pensar en cuál sería el coste del cambio en el futuro frente al coste de usar una clave subrogada en el presente. Si lo pensamos en términos económicos, utilizar una clave natural podría implicar estar firmando una hipoteca muy cara.
&lt;/p&gt;

&lt;p&gt;
  Además, como indicaba &lt;a href=&quot;https://twitter.com/pmolinam&quot; &gt;Pedro J. Molina&lt;/a&gt;, &quot;Si vas por clave natural acaba uno fácilmente con claves compuestas. Las de 4 campos ya no hacen gracia&quot;. Pero es que encima eso termina tocando mucho las narices cuando llega el momento de &quot;enchufarte&quot; a otras cosas. Es típico que el servicio que te permite asociar comentarios, likes, etc. te pida que le des un identificador único de tu entidad y nos podríamos volver locos buscando ejemplos que nos llevan a desear trabajar siempre con una clave subrogada.
&lt;/p&gt;

&lt;h2&gt;Generación de las claves subrogadas&lt;/h2&gt;

&lt;p&gt;
  Venga, vamos a suponer que a estas alturas ya estamos convencidos de que vamos a identificar a nuestras entidades con claves inmutables y subrogadas al menos algunas veces. ¿Cómo las generamos? Este punto también generó debate y en este caso no había unanimidad ni de lejos.
&lt;/p&gt;

&lt;p&gt;
  Para generar una clave subrogada podemos optar por dejar que la base de datos la genere por nosotros automáticamente cuando insertamos el registro o podemos ser nosotros desde el código los que proporcionemos la clave a la base de datos.
&lt;/p&gt;

&lt;p&gt;
  La opción clásica es que la base de datos genere el identificador por ti y listo. Podemos usar un identity, secuencia o lo que nos proporcione la base de datos que utilicemos y no nos complicamos mucho la vida. Pero hay escenarios en los que nos podría interesar recurrir a otro tipo de mecanismos.
&lt;/p&gt;

&lt;h2&gt;Mecanismos para la generación de claves subrogadas&lt;/h2&gt;

&lt;p&gt;
  Aunque podríamos ponernos muy creativos de cara a la generación de nuestras claves, hay ciertos mecanismos predominantes. No voy a posicionarme respecto a ninguno porque creo que su utilización depende mucho de los requisitos del negocio y de la infraestructura de la aplicación.
&lt;/p&gt;

&lt;h3&gt;Guids&lt;/h3&gt;

&lt;p&gt;
  Generar Guids es algo sencillo, se puede hacer desde cualquier sitio y las posibilidades de colisión son absolutamente despreciables. En principio es un mecanismo interesante ya que nos permite tener el control desde el negocio y no depender de la base de datos para su generación. Además, entre sus virtudes podemos considerar que al usar un Guid estamos utilizando un identificador no sólo a la tabla, también entre todas las tablas e incluso entre varias bases de datos. Esto habilita con mucha más facilidad escenarios de &quot;merge&quot; en los que queremos juntar datos que provienen de varias fuentes.
&lt;/p&gt;

&lt;p&gt;
  Por supuesto, también tiene sus contras, entre ellos que un Guid ocupa muchísimo más que una clave numérica y además &lt;a href=&quot;http://sqlmag.com/database-performance-tuning/clustered-indexes-based-upon-guids&quot; &gt;afecta negativamente&lt;/a&gt; al rendimiento de los índices clustered.
&lt;/p&gt;

&lt;p&gt;
  Hay mucha literatura sobre este tema en internet, incluyendo algunos intentos de análisis sobre la diferencia desde el punto de vista de rendimiento. Además debemos tener en cuenta que la implementación de base de datos que utilicemos influye muchísimo. Como ejemplo, no es lo mismo usar &lt;a href=&quot;http://krow.livejournal.com/497839.html&quot; &gt;MySQL&lt;/a&gt; que &lt;a href=&quot;http://www.informit.com/articles/printerfriendly/25862&quot; &gt;SQL Server&lt;/a&gt;.
&lt;/p&gt;

&lt;h3&gt;Numérico autoincrementado&lt;/h3&gt;

&lt;p&gt;
  Este mecanismo es uno de los más frecuentes y creo que no necesita mucha explicación. El standard SQL:2003 define los tipos IDENTITY y SEQUENCE pero dependemos de la base de datos que estemos utilizando. Por ejemplo, en MySQL está el AUTO_INCREMENT y en PostgreSQL también está el SERIAL (creo que es &quot;azucar sintáctico&quot; para definir un SEQUENCE).
&lt;/p&gt;

&lt;h3&gt;HiLo&lt;/h3&gt;

&lt;p&gt;
  A grandes rasos, con HiLo la aplicación reserva con antelación en la base de datos un rango de identificadores que serán utilizados necesite insertar nuevos registros en la base de datos. Cuando la aplicación ha usado todos los identificadores, va a la base de datos y reserva más. NHibernate usa esta técnica y también es posible usarla en Entity Framework. Entre sus ventajas está que nos permite utilizar identificadores de tipo numérico (para los que demandan rendimiento) y entre las desventajas que genera &quot;lagunas&quot; entre los identificadores generados. Si una aplicación reserva los identificadores del 1 al 10 y luego usa únicamente 5, los identificadores de 6 al 10 quedarán sin usar.
&lt;/p&gt;

&lt;h3&gt;Dependiendo de un tercero&lt;/h3&gt;

&lt;p&gt;
  Consiste en delegar en un tercero la estrategia de generación de nuestra clave. Desde nuestra aplicación, cuando queramos identificar una entidad, llamaremos a este servicio externo y nos proporcionará una identidad que será la que luego persistiremos.
&lt;/p&gt;

&lt;p&gt;
  Cuando estamos haciendo HiLo, en parte estamos utilizando este mecanismo. Aunque sea nuestra base de datos la que genera los identificadores, en realidad es un tercero (la clase que gestiona el algoritmo) el que nos los está proporcionando.
&lt;/p&gt;

&lt;p&gt;
  Un ejemplo (raro pero real) es utilizarlo cuando la persistencia se realiza sobre mecanismos que no tienen soporte de autonuméricos, delegando la generación del autonumérico sobre un tercero para luego persistir el dato. Otro escenario de uso sería si necesitamos asegurarnos de que nuestros identificadores son únicos entre varios sistemas y además queremos aplicar reglas especiales para su generación.
&lt;/p&gt;

&lt;p&gt;
  Siendo realistas, es un mecanismo que añade complejidad y no es necesario la mayoría de las veces, pero no deja de ser interesante mencionarlo.
&lt;/p&gt;

&lt;h2&gt;¿Cuál uso?&lt;/h2&gt;

&lt;p&gt;
  Según las respuestas a la conversación que originó el debate, una gran mayoría respondería &quot;secuencias numéricas autoincrementadas y no me complico&quot;. No les falta razón, pero hay veces que complicarnos es la opción menos complicada. Complicado, eh?
&lt;/p&gt;

&lt;p&gt;
  Existen muchas razones que podrían llevarnos a querer complicarnos la vida y no pretendo hacer un estudio detallado, pero al menos quiero poner algunos ejempos comunes.
&lt;/p&gt;

&lt;h3&gt;CQS&lt;/h3&gt;

&lt;p&gt;
  Si queremos usar &lt;a href=&quot;http://martinfowler.com/bliki/CommandQuerySeparation.html&quot; &gt;CQS&lt;/a&gt; (Command-Query Separation) partimos del principio de que nuestros comandos no devuelven nada. Si tenemos un comando que inserta una entidad, deberíamos saber el id de la entidad que estamos insertando antes de llamar al propio comando, ya que el comando no va a devolvernos nada.
&lt;/p&gt;

&lt;p&gt;
  Podríamos pensar que tampoco pasa nada porque un comando de inserción devuelva un valor y ya está. No voy a entrar a valorar esto, pero en cuanto queramos que el modelo de ejecución de nuestros comandos sea asíncrono (a través de una cola o similar), volvemos al problema inicial.
&lt;/p&gt;

&lt;h3&gt;Modo offline&lt;/h3&gt;

&lt;p&gt;
  Si nuestra aplicación tiene como requisito de negocio proporcionar la posibilidad trabajar offline, recurrir al servidor de base de datos para obtener el id de una entidad no es una opción.
&lt;/p&gt;

&lt;p&gt;
  Imaginemos una aplicación como Evernote. Cuando creemos una nueva nota y no tengamos conexión, ¿qué identificador tendrá esa nota entonces? Si generamos ese identificador desde el código (mediante, por ejemplo, un Guid) podremos realizar la sincronización fácilmente una vez tengamos conexión.
&lt;/p&gt;

&lt;p&gt;
  Aunque en el caso de CQS, HiLo podría ser una opción perfectamente válida, en este caso sería la opción menos recomendada ya que tendríamos la necesidad de conectarnos al servidor de base de datos si creamos tantas entidades que agotamos nuestro &quot;cupo&quot; de identificadores.
&lt;/p&gt;

&lt;h3&gt;Si no usamos SQL&lt;/h3&gt;

&lt;p&gt;
  Este caso es ignorado por muchos desarrolladores cuyo contexto profesional se limita a bases de datos SQL para persistir información. Cuando salimos del mundo SQL, muchísimos mecanismos de persistencia piden que seamos nosotros desde el código los que proporcionemos nuestros identificadores. Como ejemplo &quot;primitivo&quot; a la par que útil, si persistimos en disco tendremos que proporcionar nosotros el identificador de nuestra entidad (nombre del archivo).
&lt;/p&gt;

&lt;h1&gt;Conclusiones&lt;/h1&gt;

&lt;p&gt;
  Tenemos multitud de mecanismos para identificar nuestras entidades. Debemos conocerlos bien y hacer un uso inteligente de ellos en función de nuestros requisitos de negocio, pero nunca complicarnos la vida innecesariamente.Y muy importante, que el rendimiento únicamente sea un argumento cuando tenemos requisitos no funcionales que nos hablan de rendimiento. Hablar de rendimiento cuando no tienes requisitos relacionados con el rendimiento suele ser foco de optimizaciones prematuras.
&lt;/p&gt;

&lt;p&gt;
  Y con esto creo que termino el &quot;resumen&quot; de las cosas que se comentaron en el hilo de Twitter y algunas de las que pasaron por mi cabeza. Seguro que me dejo en el tintero muchas observaciones y muchos matices, me conformo si a alguien le vale para entender que hay vida más allá de los identificadores mutables naturales.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;http://www.modestosanjuan.com/claves-primarias-inmutabilidad-y-generacion/&quot; &gt;Este post es un cross-posting de mi blog.&lt;/a&gt;
&lt;/p&gt;
</description>
          <pubDate>2016-08-01T08:26:10+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/08/claves-primarias-inmutabilidad-y-generacion</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/08/claves-primarias-inmutabilidad-y-generacion</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en AOS2k16</title>
          <description>&lt;p&gt;
Los días 1 y 2 de Julio de 2016, la mitad del equipo Codesai estuvimos en el &lt;strong&gt;Open Space&lt;/strong&gt; de la comunidad Agile Spain, el &lt;a href=&quot;http://aos2016.agile-spain.org/&quot; &gt;AOS&lt;/a&gt;. Un evento brillantemente organizado por el capítulo gallego de la comunidad y celebrado en Santiago de Compostela. Enhorabuena a todos los organizadores por una organización perfecta. Muchísimas gracias por hacernos pasar dos días inolvidables. El lugar del evento era espectacular, en plena naturaleza. Las salas de conferencias eran acojonantes, una de ellas era una cueva, ¡literalmente... y chulísima! Hizo un tiempo buenísimo con mucho sol, cosa rara según los lugareños. Tuvimos suerte que todas las sesiones que propusimos fueron votadas y además nos lo pasamos muy bien facilitándolas.
&lt;/p&gt;

&lt;p&gt;
Primero me tocó a mí con una sesión sobre &lt;strong&gt;Principios y técnicas de diseño de software&lt;/strong&gt;. Puse en la pizarra muchos de los que yo conozco y fuimos complentando con más que los participantes fueron añadiendo. La participación y el buen ambiente hizo que el rato se pasara volando.
&lt;/p&gt;

&lt;img class=&quot;aligncenter&quot; src=&quot;/assets/CmWxdHPWcAAzmCb.jpg&quot; alt=&quot;CmWxdHPWcAAzmCb&quot; /&gt;

&lt;p&gt;
Gracias a &lt;a href=&quot;https://medium.com/@viroide/road-to-good-coder-9220960f14c5#.ho417c3fy&quot; &gt;Jon. E. Eguiluz que ha escrito sobre la sesión en su blog&lt;/a&gt;, tenemos enlaces a muchos de los temas tratados. Gracias a &lt;a href=&quot;https://twitter.com/manuelkstro&quot; &gt;Manuel Castro&lt;/a&gt; por la foto.
&lt;/p&gt;

&lt;p&gt;
Muy relacionada con mi sesión, Fran y Alfredo habían preparado otra sobre &lt;a href=&quot;https://en.wikipedia.org/wiki/Connascence_(computer_programming)&quot; &gt;Connascence&lt;/a&gt;.
&lt;/p&gt;

&lt;img class=&quot;aligncenter&quot; src=&quot;/assets/CmXqHT6XgAA0blx.jpg&quot; alt=&quot;CmXqHT6XgAA0blx&quot; /&gt;

&lt;p&gt;
Fran, al igual que yo, tenía frío dentro de la cueva y necesitaba el jersey :-). Esta charla seguramente será presentada en más eventos futuros.
&lt;/p&gt;

&lt;img class=&quot;alignright&quot; src=&quot;/assets/CmYk7aiXYAE4Z7U.jpg&quot; alt=&quot;CmYk7aiXYAE4Z7U&quot; /&gt;

&lt;p&gt;
Gracias a &lt;a href=&quot;https://twitter.com/raul_herranz&quot; &gt;Raul Herranz&lt;/a&gt; por la foto. Al final del día Ronny facilitó una sesión sobre las dificultades a la hora de aprender TDD y sus propios errores durante el proceso de aprendizaje. La sala estaba repleta. En esa sesión estábamos los cuatro y sin haberlo preparado pudimos puntualizar detalles que nos parecían relevantes a unos y otros de forma muy amena al menos para mí.
&lt;/p&gt;

&lt;p&gt;
Antes de la sesión de Ronny, el bueno de &lt;a href=&quot;https://twitter.com/dafergon&quot; &gt;David Fernández&lt;/a&gt;, compañero de Kairós DS tuvo la iniciativa de invitarme a co-facilitar una sesión sobre experiencias en la adopción de XP en equipos. Pese a ser la hora de la siesta, la participación fue alta. David propuso un modelo &quot;lean coffee&quot; y lo facilitó muy bien. ¡Gracias por la invitación David!
&lt;/p&gt;

&lt;p&gt;
A veces en eventos de la comunidad ágil existe la &lt;strong&gt;crítica de&lt;/strong&gt; que hay &lt;strong&gt;pocas sesiones técnicas&lt;/strong&gt;, tanto en AOS como en CAS. Creo que a veces es cierto pero tambien creo que es cuestión de que los que somos más técnicos tengamos la iniciativa de cambiarlo. En un Open Space uno tiene que buscar la manera de sacarle partido mediante la participación. No vale querer un evento más técnico sin proponerlo ni participar activamente en ello. Es un evento que &lt;strong&gt;se hace entre todos&lt;/strong&gt;. Creo que nuestra &lt;strong&gt;responsabilidad como developers es ayudar a reducir esa barrera&lt;/strong&gt; entre tecnología y negocio. Era la idea original de los métodos ágiles, limar esa diferencia y ser todos un equipo. A los técnicos nos toca comprender a los no-técnicos, siendo conscientes de nuestra ignorancia en otras áreas. Sin infravalorar su labor en ningún caso. Y también de ayudarles a que ellos sean conscientes de su ignorancia y puedan empatizar más con nosotros explicando las cosas en un lenguaje que les pueda llegar.  Nuestras sesiones en AOS eran todas técnicas y sin embargo pude ver a gerentes, facilitadores, agentes del cambio... Tenían interes por llevarse algo de esas sesiones, por aprender. Desde luego que no infravaloraban lo que se estaba contando sino al contrario, le veían mucho valor. En la hora de la comida incluso me dijeron que daba &quot;envidia sana&quot; oirnos hablar con tanta pasión. Creo que tiene que ver con explicarse desde un punto que busca el sentido común. Cuando el objetivo es la mejora contínua y no un rollo friki, todo el mundo pone la oreja.
&lt;/p&gt;

&lt;p&gt;
Una de los grandes despertares de este AOS para mí ha sido darme cuenta &lt;strong&gt;lo importante que es participar e AOS&lt;/strong&gt;. Llevaba desde 2013 sin hacerlo y antes de eso tambíen creo que desde 2009. Personalmente con todo lo que viajo por trabajo, cualquier evento que requiera desplazarse supone un gran esfuerzo. Tengo que justificarme a mi mismo que puedo aumentar la cuenta de días fuera de casa, dejar que la bandeja de entrada se pete, que mis clientes no puedan contar conmigo, el efecto medioambiental de los viajes...
&lt;/p&gt;

&lt;p&gt;
Hay muchísimos eventos y muy buenos. Creo que por el hecho de conocer a mucha gente de la comunidad, fuí olvidando lo importante que es tener esas conversaciones con los amigos que ya conoces, con los habituales del AOS. Tenía sensación de que era más ocio que aprendizaje. Durante un tiempo prioricé salir a otros eventos a conocer a otras personas, incluso en otros países. Ver si de esa forma aumentaba el retorno de la inversión. Estuvo bien porque he conocido a mucha gente, pero eso no es mejor que lo otro, es diferente. Volver a conversar con tantos sabios, habituales del AOS, cenando y de copas por Santiago, me aportó muchísimo valor. Me hizo darme cuenta que participar en &lt;strong&gt;AOS me garantiza el retorno de inversión&lt;/strong&gt;.  
&lt;/p&gt;

&lt;p&gt;
Debo agradecer especialmente a los amigos gallegos de la organización que me animasen a asistir a &quot;su AOS&quot; porque eso fué lo que me enganchó para comprar el billete. Reconectar con la comunidad ha sido magnifico. Desde el minuto 1 hasta la vuelta a Madrid con Yeray y Jero en coche. La gente es muy grande, muy buena gente y grandes profesionales.
&lt;/p&gt;
</description>
          <pubDate>2016-07-08T17:04:15+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/07/estuvimos-en-aos2k16</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/07/estuvimos-en-aos2k16</guid>
        </item>
      
    
      
        <item>
          <title>Nos asociamos con Kairós DS</title>
          <description>&lt;p&gt;
  &lt;strong&gt;Notición!&lt;/strong&gt; Nos asociamos con Kairós!
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Estamos de enhorabuena&lt;/strong&gt;, el equipazo de &lt;em&gt;&lt;a href=&quot;http://www.kairosds.com/&quot; &gt;Kairós DS&lt;/a&gt; se convierte en partner de Codesai&lt;/em&gt; adquiriendo una parte de la empresa.
&lt;/p&gt;

&lt;p&gt;
  En los últimos meses nos habíamos cruzado por múltiples caminos. A nosotros nos hablaban muy bien de Kairós y teníamos buenos amigos allí como &lt;a href=&quot;https://twitter.com/HelderDOliveira&quot; &gt;Helder de Oliveira&lt;/a&gt; que de paso nos daba a conocer en Kairós. Aprovechamos la ocasión para agradecerle a Helder su confianza y su apoyo, tanto a Codesai como a toda la comunidad Software Craftsmanship. Sin quererlo incluso acabamos llegando al mismo cliente desde diferentes perspectivas.
&lt;/p&gt;

&lt;p&gt;
Esta unión es una alianza estratégica: Codesai aporta su experiencia en desarrollo con XP, en testing, en el cuidado de la calidad y la mantenibilidad del software. La experiencia con formación técnica y mentoring.
&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-md-3&quot;&gt;
    &lt;img src=&quot;/assets/kairosds400x400.jpg&quot; alt=&quot;kairos_logo&quot;/&gt;
  &lt;/div&gt;
  &lt;div class=&quot;col-md-9&quot;&gt;
    &lt;p&gt;
        &lt;strong&gt;Kairós&lt;/strong&gt; aporta su &lt;strong&gt;experiencia en transformación digital en grandes organizaciones&lt;/strong&gt;, su &lt;strong&gt;gran equipo&lt;/strong&gt; de Agile Coaching, el know-how en &lt;strong&gt;grandes proyectos&lt;/strong&gt; para banca y la capacidad de llegar a clientes de un tamaño que hasta ahora era inaccesible para Codesai. Es un win-win evidente.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;strong&gt;Compartimos la oficina en &lt;a href=&quot;https://www.google.es/maps/place/Calle+de+Claudio+Coello,+78,+28001+Madrid/@40.4301529,-3.6878677,17z/data=!3m1!4b1!4m5!3m4!1s0xd42289448065b3b:0xbb9d75b79f81fb22!8m2!3d40.4301529!4d-3.685679https://www.google.es/maps/place/Calle+de+Claudio+Coello,+78,+28001+Madrid/@40.4301529,-3.6878677,17z/data=!3m1!4b1!4m5!3m4!1s0xd42289448065b3b:0xbb9d75b79f81fb22!8m2!3d40.4301529!4d-3.685679&quot; &gt;Madrid en la calle Claudio Coello, 78.&lt;/a&gt;&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Esta alianza no cambia nuestros valores ni principios, ni la forma en que trabajamos. Lo que nos permite es crecer&lt;/strong&gt; a un tamaño suficiente para que cualquier tipo de empresa pueda contar con nosotros. Nuestro catalogo de servicios crece, &lt;strong&gt;ampliamos la oferta para nuestros clientes manteniendo el nivel de calidad.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Los vamos a celebrar con varios &lt;strong&gt;eventos en la oficina: un curso técnico en abierto a finales de Julio, un evento de comunidad y otro de networking con nuestros clientes y amigos.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Ya sabes, ahora &lt;strong&gt;Codesai&lt;/strong&gt; y &lt;strong&gt;Kairós&lt;/strong&gt;, son buenos amigos :-)
&lt;/p&gt;
</description>
          <pubDate>2016-06-22T07:53:11+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/06/nos-asociamos-con-kairos-ds</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/06/nos-asociamos-con-kairos-ds</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Pamplona Software Craftsmanship 2016</title>
          <description>&lt;figure&gt;
    &lt;img src=&quot;/assets/ClVQUOAWYAQopZv-1024x768.jpg&quot; alt=&quot;Gorka, Pablo e Iker en la apertura&quot; /&gt; 
    &lt;figcaption&gt;&lt;strong&gt;Gorka, Pablo e Iker en la apertura&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
  El pasado fin de semana, 17 y 18 de Junio, buena parte del equipo Codesai estuvo en &lt;a href=&quot;http://pamplonaswcraft.com/&quot; &gt;Pamplona Software Craftsmanship 2016&lt;/a&gt;. Eventazo de categoría. Este evento fue organizado por Iker, Gorka y Pablo, los artesanos de &lt;a href=&quot;http://540deg.com/&quot; &gt;540deg&lt;/a&gt;. Ellos se inspiraron en Socrates Canaries 2016, evento que tuvo lugar en Las Palmas en Marzo. Vinieron al evento y en las conversaciones de pasillo y bar se animaron a montar un evento similar en su tierra. Poco después nos llegó invitación para ser ponentes en el evento. Y lógicamente con lo majos que son no pudimos negarnos. Y menos mal porque ha sido un evento muy bueno. A diferencia de Socrates que es 100% open space, el de Pamplona sí tenía algunos speakers invitados además de haber lugar para open space. Con la agenda de eventos tan apretada que tenemos, invitarnos directamente fue una buena forma de asegurarse nuestra participación por lo que estamos doblemente agradecidos. El hashtag fue &lt;a href=&quot;https://twitter.com/search?q=scpna&quot; &gt;#scpna&lt;/a&gt;, a través del cual pueden encontrarse fotos y comentarios realizados en vivo.
&lt;/p&gt;

&lt;p&gt;
  En el tren coincidimos unos cuantos amigos en la cafetería y pudimos comprobar que los de Renfe no están bien preparados para la ocasión porque se les acabó la cerveza antes de llegar a Pamplona :-D
&lt;/p&gt;

&lt;p&gt;
  Muy buen ambiente desde el viaje, aprovechando además para conocer a los demás ponentes y participantes. Al llegar nos encontramos con un montón de amigos para cenar y nos dieron las tantas.
&lt;/p&gt;

&lt;p&gt;
  Tanto Alfredo como Modesto como yo, contamos con una hora entera como ponentes. En mi caso quise convertir la sesión en un coloquio donde la gente pudiera dar feedback y el nivel de participación fue muy bueno. El tiempo se me hizo cortísimo. La mitad de las cosas que quería contar se quedaron fuera y es que nunca antes había contado todas estas cosas y no había tenido oportunidad de medir los tiempos. Mi buen amigo Antonio de la Torre me comentó que me faltó una conclusión al estilo &quot;call to action&quot;,  comentario que agradezco mucho. Cualquier otro feedback es bienvenido. La mayoría de las sesiones las grabaron entre el Planetario y &lt;a href=&quot;http://codely.tv/&quot; &gt;Codely.tv&lt;/a&gt;, y estoy deseando verlas porque me perdí 4 charlas que me interesaban un montón, un poquito a sabiendas de que eran en la mejor sala para ser grabadas y confiando en que la grabación será buena. Así que estoy deseando que las publiquen.
&lt;/p&gt;

&lt;p&gt;
  El open space tuvo un alto nivel de participación con sesiones muy interesantes, era dificil escoger a qué sesión entrar. Fue estupendo reencontrarse con amigos que llevaba años sin ver y desvirtualizar a grandes profesionales compañeros del gremio que ya seguía por las redes. Fue estupendo conocer a más cracks de &lt;a href=&quot;http://karumi.com/&quot; &gt;Karumi&lt;/a&gt; (que por cierto a la charla de Pedro Gómez sí que pude ir y me encantó) y a parte de &lt;a href=&quot;http://www.47deg.com/&quot; &gt;47deg&lt;/a&gt;. Algunos slots me los perdí mientras hablaba con gente por los pasillos, cosa que sucede mucho en los open space, que las conversaciones son una parte muy muy enriquecedora del evento. Lo más difícil del open space es vencer la sensación de impotencia de no poder estar en todos sitios a la vez. En el segundo día lo conseguí y me eché una siesta despues de comer que me permitió luego casi empatar la cena de cierre con mi vuelo de amanecida. Y es que la organización del evento lo hizo todo a la perfección, hasta el último momento. Son grandísimos anfitriones. Y lo más llamativo es que nunca les vi nerviosos, estan tranquilotes y disfrutando del evento. Me llamó muchísimo la atención que en la zona de encuentro, además de haber cafés, zumos y fruta, había un grifo de cerveza y tambien cervezas patrocinadas por 47deg. Cerveza disponible casi las 24 horas :-D
&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/assets/ClTN8YmXEAAxxaZ-1024x276.jpg&quot; alt=&quot;Retrospectiva final&quot; /&gt;
    &lt;figcaption&gt;
    &lt;strong&gt;Retrospectiva final&lt;/strong&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;
  Fue curioso que en la retrospectiva del primer día a penas hubieron puntos a mejorar y los pocos que salieron estaban corregidos al día siguiente. Por lo tanto en la retrospectiva de cierre no hubo ni un solo punto común de mejora a destacar. Una organización brillantísima, excepcional.
&lt;/p&gt;

&lt;p&gt;
  Como parte del open space tuve ocasión de facilitar un taller de refactoring de 2 horas donde practicamos Parallel Change y Narrow Change, el mismo que habíamos hecho Pawel Duda y yo en Socrates con alguna mejora. Fue muy divertido, gracias a todos por participar en el taller.
&lt;/p&gt;

&lt;p&gt;
  Estoy muy contento de ver que tanto Ronny como Miguel y Dani, nuestros aprendices, propusieron varias sesiones en el open space y que además salieron votadas y se desarrollaron muy bien. Da gusto ver a la gente joven progresar.
&lt;/p&gt;

&lt;p&gt;
  Al final del evento la gente del Planetario de Pamplona que fueron majísimos todo el evento, nos dieron un estupendo paseo por el cielo y nos proyectaron un vídeo que me transportó 20 años atrás a la demo scene del Amiga, de cuando la Euskal Party y antes incluso. Para los más jóvenes dejo aquí la &lt;a href=&quot;https://www.youtube.com/watch?v=c5kuYfTCGLg&quot; &gt;famosa demo de Space Balls &lt;/a&gt; que es del 91 o 92. La mayoría de esta gente programaba en ensamblador con máquinas de medio mega de ram y secuenciadores de 4 pistas para la música. Gran cierre.
&lt;/p&gt;

&lt;p&gt;
  ¡Muchas gracias a todos por hacer el evento posible!
&lt;/p&gt;
</description>
          <pubDate>2016-06-21T14:15:01+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/06/estuvimos-en-pamplona-software-craftsmanship-2016</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/06/estuvimos-en-pamplona-software-craftsmanship-2016</guid>
        </item>
      
    
      
        <item>
          <title>Estuvimos en Fon</title>
          <description>&lt;p&gt;Hace unos meses tuvimos la suerte de ser contratados por &lt;a href=&quot;https://fon.com/&quot;&gt;Fon&lt;/a&gt; para impartir un &lt;a href=&quot;/curso-de-tdd/&quot;&gt;curso de TDD&lt;/a&gt; a uno de sus equipos de desarrollo en Madrid. Una oficina chulísima y un equipo entregado que prestó atención máxima desdel el minuto 1.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/fon_1.jpg&quot; alt=&quot;Miguel ayudando a una pareja&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Fon es una empresa de la que he oído hablar practicamente desde sus orígenes porque sonaba mucho en el mundillo geek desde siempre. Tenían fama de hacer las cosas bien. Así que tenía ganas de visitarles y ver qué se contaban hoy en día donde el Wifi ya no parece tan importante. Sin embargo me contaron que lo están petando con el roaming wifi en varios países.&lt;/p&gt;

&lt;p&gt;Lo único que me faltó para que hubiese salido todo del 10 es conocer a &lt;a href=&quot;https://twitter.com/dbrandib&quot;&gt;Daniel Brandi&lt;/a&gt; que justamente esa semana estaba en un evento en Londres y no nos pudimos ver. Me sorprendió gratamente que muchos de los participantes en el curso ya me conocían y se habían preparado preguntas para sacarle el máximo partido a esos dos intensos días de formación.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/fon_2.jpg&quot; alt=&quot;Trabajando una kata&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Agradezco especialmente a &lt;a href=&quot;https://www.linkedin.com/in/joan-fisbein-1b515&quot;&gt;Joan Fisbein&lt;/a&gt; la atención, el apoyo prestado y las agradables conversaciones durante la comida.&lt;/p&gt;

&lt;p&gt;Parece que el curso cambió la forma en que el equipo ve los tests, tanto en calidad como en cantidad. La gente se dió cuenta que la cobertura no es un objetivo en sí mismo sino que lo importante es crear unos tests mantenibles que mantengan un buen compromiso entre seguridad y mantenibilidad.&lt;/p&gt;

&lt;p&gt;Las conversaciones fueron muy interesantes y la gente muy maja.&lt;/p&gt;

&lt;p&gt;Además, en este curso; pudo venir conmigo nuestro aprendiz &lt;a href=&quot;https://twitter.com/mangelviera&quot;&gt;Miguel A. Viera&lt;/a&gt; y facilitar alguno de los ejercicios en el segundo día. Miguel se quedó alucinado con la oficina.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/fon_3.jpg&quot; alt=&quot;Trabajando otra kata&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ahora mismo &lt;strong&gt;Fon está buscando desarrolladores Java senior&lt;/strong&gt;. Es un buen momento para enviarles un CV si estás buscando nuevos retos.&lt;/p&gt;
</description>
          <pubDate>2016-05-31T22:57:41+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/05/estuvimos-en-fon</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/05/estuvimos-en-fon</guid>
        </item>
      
    
      
        <item>
          <title>The Ohce kata, a short and simple exercise to practice outside-in TDD using test doubles</title>
          <description>&lt;p&gt;I created this short and simple kata to practice outside-in TDD using test doubles for a mentoring &lt;a href=&quot;http://alvarogarcia7.github.io/&quot;&gt;Álvaro&lt;/a&gt; and I are doing in &lt;a href=&quot;https://twitter.com/magento&quot;&gt;Magento Barcelona&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ohce&lt;/strong&gt; is a console application that echoes the reverse of what you input through the console.&lt;/p&gt;

&lt;p&gt;Even though it seems a silly application, &lt;strong&gt;ohce&lt;/strong&gt; knows a thing or two.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;When you start oche, it greets you differently depending on the current time, but only in Spanish:
    &lt;ul&gt;
      &lt;li&gt;Between 20 and 6 hours, &lt;strong&gt;ohce&lt;/strong&gt; will greet you saying:  &lt;em&gt;¡Buenas noches &amp;lt; your name &amp;gt;!&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;Between 6 and 12 hours, &lt;strong&gt;ohce&lt;/strong&gt; will greet you saying:  &lt;em&gt;¡Buenos días &amp;lt; your name &amp;gt;!&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;Between 12 and 20 hours, &lt;strong&gt;ohce&lt;/strong&gt; will greet you saying:  &lt;em&gt;¡Buenas tardes &amp;lt; your name &amp;gt;!&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;When you introduce a palindrome, &lt;strong&gt;ohce&lt;/strong&gt; likes it and after reverse-echoing it, it adds &lt;em&gt;¡Bonita palabra!&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ohce&lt;/strong&gt; knows when to stop, you just have to write &lt;em&gt;Stop!&lt;/em&gt; and it’ll answer &lt;em&gt;Adios &amp;lt; your name &amp;gt;&lt;/em&gt; and end.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is an example of using &lt;strong&gt;ohce&lt;/strong&gt; during the morning:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ohce Pedro
&amp;gt; ¡Buenos días Pedro!
$ hola
&amp;gt; aloh
$ oto
&amp;gt; oto
&amp;gt; ¡Bonita palabra!
$ stop
&amp;gt; pots
$ Stop!
&amp;gt; Adios Pedro
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I hope you enjoy doing it.&lt;/p&gt;
</description>
          <pubDate>2016-05-25T07:00:00+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/05/ohce-kata</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/05/ohce-kata</guid>
        </item>
      
    
      
        <item>
          <title>Lanzamos Codesai con mucha ilusión</title>
          <description>&lt;p&gt;&lt;strong&gt;Después de dos años trabajando bajo la marca de CB&amp;amp;A (Carlos Blé y Asociados)&lt;/strong&gt; ha llegado el momento de crear algo más grande, una marca que proporcione a nuestros clientes la confianza de que puede funcionar sin Carlos, cuando haga falta. Una marca donde el interés del grupo y de la comunidad está por encima de los individuos. &lt;strong&gt;Un grupo que hace de su trabajo su pasión. Donde trabajo y afición son la misma cosa.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
Aunque sea con el mismo núcleo, queremos dar a conocer a todo el mundo que este grupo de profesionales se ha consolidado y es un equipo bien alineado, maduro y más ilusionado que nunca por ayudar a los demás. Por crear grandes productos. Por impactar en la sociedad. Queremos subir el nivel del sector de desarrollo de software en nuestro país y llegar a innovar y exportar conocimiento fuera de él.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Nuevas alianzas, de las cuales publicaremos detalles pronto&lt;/strong&gt;, nos permiten tener una estratégica &lt;strong&gt;oficina en pleno centro de negocios de Madrid&lt;/strong&gt;. Nos permiten llegar a clientes que antes eran imposibles.&lt;/p&gt;
&lt;p&gt;
La consolidación de &lt;strong&gt;Codesai&lt;/strong&gt; como empresa, junto con su red de partners, van a multiplicar nuestra impacto, nuestra capacidad de cambiar el mundo en que vivimos.&lt;/p&gt;
&lt;p&gt;
Arrancamos nueva etapa, Codesai se va a hacer notar. Estad atentos que pronto habrá fiesta de inauguración!&lt;/p&gt;
&lt;p&gt;
Ya sabes que &lt;strong&gt;puedes contar con nosotros&lt;/strong&gt;, no sólo en Madrid sino en cualquier lugar... sólo dinos &lt;strong&gt;¿en qué podemos ayudarte?&lt;/strong&gt;&lt;/p&gt;
</description>
          <pubDate>2016-05-20T15:48:12+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/05/lanzamos-codesai-con-ilusion</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/05/lanzamos-codesai-con-ilusion</guid>
        </item>
      
    
      
        <item>
          <title>Event bubbling in C#</title>
          <description>&lt;p&gt;How to propagate an event from a low level class to a top level one:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/09a0bb5b79de8c784064f8f616bca6b4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Events can only be raised from within the declaring type. Unfortunately they can’t be be passed in as arguments to methods. Only &lt;strong&gt;+=&lt;/strong&gt; and &lt;strong&gt;-=&lt;/strong&gt; operators are allowed out of the declaring type. One way to stub out the event could be through inheritance:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/cbe175b360cae40a89ea621a5f42380a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;But declaring the event as virtual and then overriding it, is very tricky: replacing the call to &lt;strong&gt;RaiseEvent&lt;/strong&gt; to &lt;strong&gt;DoSomething&lt;/strong&gt;, makes the test fail! Looks like events where not designed to be overridden.&lt;/p&gt;

&lt;p&gt;A better approach would be:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/dab0d2b7a2914d66177e505588af344e.js&quot;&gt;&lt;/script&gt;

</description>
          <pubDate>2016-04-08T16:12:57+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/04/event-bubbling-in-c</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/04/event-bubbling-in-c</guid>
        </item>
      
    
      
        <item>
          <title>Windows apps development best practices</title>
          <description>&lt;p&gt;I don’t really know whether they are the best practices to be honest, and certainly there is a lot for me to learn but these are principles and practices that work well for us in the development of a complex native Windows App (Windows 8.1+) using C# and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel&quot;&gt;MVVM pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Files in my example (namespace + classname) :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Example.Views.App.xaml.cs (Main app class)&lt;/li&gt;
  &lt;li&gt;Example.Views.Vehicle.xaml (View)&lt;/li&gt;
  &lt;li&gt;Example.Views.Vehicle.xaml.cs (View’s Codebehind)&lt;/li&gt;
  &lt;li&gt;Example.ViewModels.Vehicle.cs (View model)&lt;/li&gt;
  &lt;li&gt;Example.Domain.Vehicle.cs (Domain model)&lt;/li&gt;
  &lt;li&gt;Example.ViewModels.AppState.cs (In-memory app state)&lt;/li&gt;
  &lt;li&gt;Example.Views.NavigationService.cs (Our custom navigator)&lt;/li&gt;
  &lt;li&gt;Example.Views.NavigationParameters.cs (Bag of parameters to be sent to the target view)&lt;/li&gt;
  &lt;li&gt;Example.Domain.EventBus.cs (Our custom pub-sub implementation, a singleton)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Page navigation is performed by the framework:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5d9f948ae6c0b1cb12c8a4f57d3218e6.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The first parameter is the type of the target Page and the second is an “object” intended to send any custom parameter. Such parameter is received as an argument of &lt;em&gt;OnNavigatedTo&lt;/em&gt; method in the target page.&lt;/p&gt;

&lt;p&gt;The code above is used to navigate from &lt;em&gt;App.xaml.cs&lt;/em&gt; (Main page) to &lt;em&gt;Vehicle&lt;/em&gt; (Page).&lt;/p&gt;

&lt;p&gt;The NavigationService is an indirection level that sends the ViewModel to the View as the context object. It’s used pretty much like &lt;em&gt;Frame.Navigate&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/8be24263b325c717456f06ca9512bb39.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Implementation (&lt;em&gt;NavigationService.cs&lt;/em&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2540086e4a2a530794d5d0142e9f24e4.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is how the view model is received in Vehicle’s codebehind (&lt;em&gt;Vehicle.xaml.cs&lt;/em&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3a60cbc9d1f47b75fd5444c556d74ceb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Principles applied in the code snippet above:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;DataContext is set in the last step of the method, not before. DataContext is set either in the codebehind or in xaml, but not in both places at the same time. If the DataContext is set in the xaml (DataContext=”SomeProperty”) and also in the codebehind, you can’t guarantee which data will be finally set, race conditions could happen.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pages and UI controls in general must not contain state. Avoid any field in the codebehind holding a reference to the view model. This is to prevent race conditions. We rather create a getter instead: &lt;script src=&quot;https://gist.github.com/trikitrok/033216e966ba3702384f2fe9dd47f34b.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Avoid subscribing the codebehind to the EventBus, use the view model as the listener. Life cycle of the pages is controlled by the framework - this is specially important when caching pages via &lt;em&gt;NavigationCacheMode=”Required”&lt;/em&gt;. Sending a reference to the EventBus will prevent the garbage collector from cleaning up the Page instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avoid global statics&lt;/strong&gt;: Although there is a single instance of AppState class - is a global singleton, we inject it into every view model that requires read or write access rather than having direct static references. The Factory knows the AppState singleton and injects it to the viewmodels. Although two different views may require the same data, we try not to store everything in the AppState but rather cache the service methods retrieving the required data and then injecting the same instance service to both viewmodels. The amount of data kept in the AppState should be minimal, basically it should contain identifiers that view models understand in order to pull data from the services. Sometimes it contains more data to avoid time consuming transformations or calculations, that’s fine, it’s a trade off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom controls:&lt;/strong&gt; We ended up having our own custom pages, inheriting the Page control to remove duplication from initialization process. One of such inheritors is generic: _CachedPage&lt;T&gt;_, where T is the type of ViewModel. However in xaml you can&apos;t define a page inheriting from a generic class. To work around this minor issue we create an intermediate empty class:&lt;/T&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/7baacb8c1ae3566670d36e31f88a4e84.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Then in xaml we can set the type of our page to be CachedVehiclePage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nested user controls:&lt;/strong&gt; When a Page contains a user control, the DataContext of that user control is the same than the Page’s one. Neither the codebehind or the xaml of user control should overwrite the DataContext. The DataContext should not be set programmatically it’s just inherited from the parent container. Otherwise there could be race conditions and memory leaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data binding:&lt;/strong&gt; We don’t bind domain models directly to the GUI. The main reason is that double way binding requires public setters. Sometimes we create a bindable object that wraps the domain model exposing only ome properties. But we often create custom bindable objects from the domain model for the specific purposes of the view.&lt;/p&gt;

&lt;p&gt;I’ll update this post with more stuff that is working well for us.&lt;/p&gt;
</description>
          <pubDate>2016-02-24T14:39:27+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/02/windows-apps-development-best-practices</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/02/windows-apps-development-best-practices</guid>
        </item>
      
    
      
        <item>
          <title>A code review is not like watching a football match</title>
          <description>&lt;p&gt;In my experience a &lt;strong&gt;code review must have a goal&lt;/strong&gt;. Some common goals are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Telling others how you solved a common problem.&lt;/li&gt;
  &lt;li&gt;Warning others about certain perils (i.e race conditions, coupling…)&lt;/li&gt;
  &lt;li&gt;Asking concrete questions. Implementation or design questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you expose some code to your colleagues in a meeting room, you should know exactly what you want to get from that activity. You want to learn, to tech or to warn others basically. Otherwise, if you just open up some code and ask your colleagues what’s their opinion about the code, then everyone will say something. Exactly like watching a football match with friends, everyone has his/her opinion on how the coach should manage the team, how players should play… no matter how good the team play, there will be always someone opinionated bullshit. The code review will be frustrating and not very productive.&lt;/p&gt;

&lt;p&gt;Remember to &lt;strong&gt;prepare a list of questions or tips to tell others&lt;/strong&gt;, together with the code you want to share, before going to the code review.&lt;/p&gt;
</description>
          <pubDate>2016-02-24T10:52:29+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/02/a-code-review-is-not-like-watching-a-football-match</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/02/a-code-review-is-not-like-watching-a-football-match</guid>
        </item>
      
    
      
        <item>
          <title>We visited Scytl</title>
          <description>&lt;p&gt;In October 2015, just two months before the Spanish elections I was lucky to visit &lt;a href=&quot;http://www.scytl.com/&quot;&gt;Scytl&lt;/a&gt; and work there as a consultant for a week. Thanks to my good friends &lt;a href=&quot;https://twitter.com/manucervello&quot;&gt;Manu Martin&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/alvarobiz&quot;&gt;Alvaro Garcia&lt;/a&gt; who are currently working in there as agile coach and developer respectively. I met a different team each day of the week, it was quite challenging and interesting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/tdd-course-scytl-2015.jpg&quot; alt=&quot;collage course images&quot; /&gt;&lt;/p&gt;

&lt;p&gt;More often than not, when I visit companies, I get to see a significant amount of coding horrors and technical debt. So I was curious about Scytl because I knew they were going to collect and count my vote together with other 30 million more two months later. They were the IT company designated to  collect and count the votes in the Spanish elections - among many other things like the website with the reports…&lt;/p&gt;

&lt;p&gt;I must say that I really liked what I saw, they are brilliant security experts, very professional. Citizens’ vote was absolutely private and secure. I was confident that my decision as voter was secure, that I could trust their software. It’s a very good feeling… software one can trust finally!&lt;/p&gt;

&lt;p&gt;And yes, two months later they did a fantastic job, and they even broke the voting count speed record. Congratulations!&lt;/p&gt;

&lt;p&gt;One of the teams I worked with was exactly the one in charge of collecting the votes. They had really good architecture and design questions for me. It was a challenge. Their chosen solution was very smart, I liked its simplicity. There was a lot of pressure on this team and I explained how important it is to have some slack time in order to step back for a little while and rethink decisions. Too much pressure is harmful in my experience, the best ideas come up when the brain is relaxed.&lt;/p&gt;

&lt;p&gt;I also worked with the team in charge of counting votes and I got to see the &lt;a href=&quot;https://en.wikipedia.org/wiki/D&apos;Hondt_method&quot;&gt;D’hondt algorithm&lt;/a&gt;, something totally new for a democracy illiterate like me. We had a very nice mob programming session with the whole team in the meeting room. People were skeptical about mob programming at first but they quickly grasped its benefits, it was a way to find out team conventions for example.&lt;/p&gt;

&lt;p&gt;On the third or forth day I also spent the day with the mob, this time with another team. The focus was on refactoring and unit testing strategies apart from a code review. We had the chance to explore together some of the new features of Java 8 too. I emphasized the importance of learning the IDE’s shortcuts and the automatic refactorings it provides - it was IntelliJ in this case. Nice to code with young people willing to learn and improve.&lt;/p&gt;

&lt;p&gt;I emphasized the fact that communication among co-located teams is more effective face to face. Pairing for a while to integrate a new feature from the other team or some API change, feels nicer than sending emails back and forth. Dog fooding among teams could help improve collaboration given that some teams act as a kind of “customer” to others.&lt;/p&gt;

&lt;p&gt;There was also a session with a group to discuss about values, principles, professionalism and motivation. An exchange of opinions and points of view. Unexpected and very enriching.&lt;/p&gt;

&lt;p&gt;I didn’t know that teams are multicultural with people from distinct nationalities. English is the official spoken language. Although my English is not too bad for a quick chat, I had some trouble understanding and communicating with some people from other cultures.  It reminded me of how tough it could be to work with people from other cultures, specially when English is not the native spoken language of none of us.&lt;/p&gt;

&lt;p&gt;Scytl’s people were excellent hosts, very welcoming and friendly. Thank you for a remarkable week!&lt;/p&gt;
</description>
          <pubDate>2016-01-14T00:05:42+00:00</pubDate>
          <link>https://www.codesai.com/posts/2016/01/estuvimos-en-scytl</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2016/01/estuvimos-en-scytl</guid>
        </item>
      
    
      
        <item>
          <title>Polymorphic test setup with template method</title>
          <description>&lt;p&gt;We had a kind of duplication in our tests that we didn’t know how to deal with. The refactoring &lt;strong&gt;Introduce Polymorphic Creation with Factory Method&lt;/strong&gt; explained by &lt;a href=&quot;https://www.industriallogic.com/people/joshua&quot;&gt;Joshua Kerievsky&lt;/a&gt; in his brilliant &lt;a href=&quot;https://industriallogic.com/xp/refactoring/&quot;&gt;book “Refactoring to Patterns”&lt;/a&gt; gave us the solution to avoid duplicated tests.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f1e11f975ac2ac589bcd5f1f011f463b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;These tests are very similar, the differences are in lines 8 and 25, and also in lines 13 and 30. The first test tries to change the color of a configuration, whereas the second one tries to change the interior.
Part of the handling business logic is the same. This is just one scenario but we had many others with the same expected behavior for color, interior, equipment, and more. Eventually there would be a lot of &lt;strong&gt;duplication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After refactoring, we have a base abstract class with the tests, exposing &lt;strong&gt;template methods&lt;/strong&gt; that derived classes have to implement in order to populate the catalog and also to execute the corresponding action:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/2c303a4fa5b02a3330882d443645751f.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The base class &lt;em&gt;ConfigurationTests&lt;/em&gt; contains just helper methods such as &lt;em&gt;ExecuteChangeColor&lt;/em&gt;, or &lt;em&gt;ExecuteChangeInterior&lt;/em&gt;, but no tests at all. Otherwise tests would run twice.&lt;/p&gt;
</description>
          <pubDate>2015-12-21T16:30:19+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/12/polymorphic-test-setup-with-template-method</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/12/polymorphic-test-setup-with-template-method</guid>
        </item>
      
    
      
        <item>
          <title>Refactorizando Try - Catch usando Javaslang</title>
          <description>&lt;p&gt;Hace unos días, empecé un proyecto personal para mejorar algunas tecnologías, como por ejemplo, conexión con bases de datos o trabajar con &lt;a href=&quot;http://sparkjava.com/&quot;&gt;Spark&lt;/a&gt; para hacer un servicio Rest.&lt;/p&gt;

&lt;p&gt;Empecé con una idea muy sencilla, ya que lo que quería era empezar cuanto antes y, más adelante, ir incorporando nuevas &lt;em&gt;features&lt;/em&gt; y encontrarme con problemas como ¿por qué hice esto de esta forma y no de esta otra?, ó también, “por tomar una determinada decisión me ha surgido un problema grande a la larga”.&lt;/p&gt;

&lt;p&gt;La idea principal, es tener una tienda online donde tendré usuarios y productos, donde los almacenaré en una base de datos y proporcionar un servicio Rest.&lt;/p&gt;

&lt;p&gt;Primero, empecé por hacer un CRUD usando JDBC donde tengo una tabla de usuarios:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/8071f5ae2ca64b277b8071e82618aa57.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Y mi clase User:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/d69f3abb6d4524804155295b35aac763.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Una vez implementado el CRUD y refactorizado el código, me encontré con que no me podía quitar los bloques de &lt;em&gt;try/catch&lt;/em&gt;, lo cuál me frustró mucho porque me parecían bastante verbosos. Pero, por casualidad o por cosas del destino, &lt;a href=&quot;https://twitter.com/rubendm23&quot;&gt;Rubén&lt;/a&gt; compartió unos vídeos sobre patrones de diseño con Java 8, de los que quiero destacar la &lt;a href=&quot;https://www.youtube.com/watch?v=K6BmGBzIqW0&amp;amp;feature=youtu.be&quot;&gt;charla&lt;/a&gt; de &lt;a href=&quot;https://twitter.com/mariofusco&quot;&gt;Mario Fusco&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Entre otras cosas, recomendó &lt;a href=&quot;http://javaslang.com/&quot;&gt;javaslang&lt;/a&gt;, una biblioteca funcional que añade, pequeñas, pero importantes mejoras a Java 8. Propone un ejemplo con la clase Try&amp;lt;T&amp;gt;, dicha clase es una mónada que puede devolver dos tipos de objetos: &lt;em&gt;Success&lt;/em&gt; (objeto que contiene el valor) o &lt;em&gt;Failure&lt;/em&gt; (objeto que contiene la excepción). Además, se le pueden aplicar funciones como &lt;em&gt;map&lt;/em&gt; o &lt;em&gt;andThen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Así era como se insertaba un usuario en la base de datos:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/1163a7bc7d9e19b39cd37ac1d18fe872.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Y este es el método que establecía la conexión con la base de datos:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/55e8f82e7a3ae42e4885924410a3b293.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;¡Cuántos &lt;em&gt;try/catch&lt;/em&gt;! Vamos a refactorizar para dejar un código más limpio y legible donde cualquier persona pueda leerlo y tener una idea de cómo funciona con solo echarle un vistazo. Empecemos con el método que establecía la conexión:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/f681f1e2118c0a229ef5e20822d7fcfb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Y finalmente, con el método que inserta, extrayendo más métodos para dejar el código más limpio y legible.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/12953edfb24a89c35ebcf0b1e991107e.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;En caso de que querramos controlar las excepciones, basta con llamar a la función &lt;strong&gt;onFailure(Consumer&amp;lt;Throwable&amp;gt;)&lt;/strong&gt;. Por ejemplo:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/b88bbf58376cdd916eed7687e408be49.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Personalmente, me ha gustado mucho haber descubierto esta manera de hacerlo, ya que me centro más en &lt;strong&gt;qué&lt;/strong&gt; quiero hacer en vez de &lt;strong&gt;cómo&lt;/strong&gt; lo quiero hacer. Y además, mejora muchísimo la legibilidad del código.&lt;/p&gt;

&lt;p&gt;Por último, me gustaría recordar que el proyecto es para aprender y cualquier &lt;em&gt;feedback&lt;/em&gt; será muy bien recibido :D&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Link proyecto: &lt;a href=&quot;https://github.com/JoseDeniz/A2Ztore&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Link: Otro &lt;a href=&quot;https://github.com/JoseDeniz/Java-8-Basic-Examples/blob/master/src/main/java/javaslang/try_monad_example/ReadLinesFromFileExample.java&quot;&gt;ejemplo&lt;/a&gt; usando la clase Try&lt;/li&gt;
&lt;/ul&gt;
</description>
          <pubDate>2015-12-15T16:10:03+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/12/refactorizando-try-catch-usando-javaslang</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/12/refactorizando-try-catch-usando-javaslang</guid>
        </item>
      
    
      
        <item>
          <title>Pairing: don’t have to always agree on a plan</title>
          <description>&lt;p&gt;So your pair is proposing a route or plan that you don’t agree on. Am talking about a refactoring, a redesign or just the way to test drive the next feature. You have told him your reasons no to agree with him and there is no way to get to an agreement. It’s perhaps frustrating because you believe his strategy will fail but he definitely wants to proceed that way. What do you do? Argue forever?&lt;/p&gt;

&lt;p&gt;I don’t think you have to always agree on the path you are going to walk. The important thing is that both understand the plan so that driver and navigator can help each other get there. In those situations I end up saying… &lt;em&gt;I believe this approach is not the best and I would try out something else&lt;/em&gt; - something I explained already… &lt;em&gt;but anyway, I’ll help you with your idea, let’s do it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Several times my pairs have proven that they were right and the plan was effective. Some other times it wasn’t a good idea, but we built a trustworthy relationship, a supportive one.&lt;/p&gt;
</description>
          <pubDate>2015-12-02T09:25:44+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/12/pairing-dont-have-to-agree-on-the-plan</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/12/pairing-dont-have-to-agree-on-the-plan</guid>
        </item>
      
    
      
        <item>
          <title>Object references, state and side effects</title>
          <description>&lt;p&gt;C#, Java and other languages have the same behaviour when it comes to reference types.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/10bc0953de73897f577e3c69b1142e36.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The dot symbol after the variable name (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance1&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance2&lt;/code&gt;) accesses the actual&lt;/p&gt;

&lt;p&gt;object referenced by that variable. So before the dot, we have a variable referencing an object, and&lt;/p&gt;

&lt;p&gt;after the dot we have the actual object.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/206e4d745f2aed7e9dc9f87d465c8679.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Means: get reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instace1&lt;/code&gt;, then access the object, then access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someField&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Passing objects to functions has exactly the same behaviour, function parameters behave like variables assigned to the original arguments.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/3a49b9f20cd89c226f6cdeecb2ffe880.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Instances of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SomeClass&lt;/code&gt; are mutable because the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someField&lt;/code&gt; may be changed.&lt;/p&gt;

&lt;p&gt;This mutation may happen by mistake as a result of an uncontrolled access to the object via some copy of its reference ( a case of &lt;a href=&quot;https://en.wikipedia.org/wiki/Aliasing_(computing)&quot;&gt;aliasing&lt;/a&gt;), causing unexpected side effects like defects and memory leaks.&lt;/p&gt;

&lt;p&gt;While the application code can reach an object - has some reference to it - the garbage collector can’t free the memory allocated to that object.&lt;/p&gt;

&lt;p&gt;Short version of our desktop app architecture as an example:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/48fcdf88c57df50d3c7a510afedf4e4b.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The life cycle of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; instance is controlled by the framework, not by us. It may create a new instance every time the view is shown on screen and destroy the instance as it disappears. However we are adding a reference to the static list of subscribers in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventBus&lt;/code&gt;. Until the subscribers list is flushed, the garbage collector won’t be able to set memory free for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; instances, even though the view may not be even being displayed. Opening that view many times will increase the memory consumption every time, i.e., causing a memory leak. In this particular case we unsubscribe the instance from the bus before hiding the view:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/e0e44c713365200b3826198133e8a1bc.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In the case of the bus there isn’t much we can do to avoid having two references to the same object in two different places, we have to be aware of this behavior. In C# there is the concept of &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms404247(v=vs.110).aspx&quot;&gt;Weak Reference&lt;/a&gt; but as far as I know we can’t use it on WinRT (tablets).&lt;/p&gt;

&lt;p&gt;In some other cases though we may avoid side effects by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Avoiding more than one reference per object, avoid state.&lt;/li&gt;
  &lt;li&gt;Keeping variables local, avoid instance variables (fields).&lt;/li&gt;
  &lt;li&gt;When the object is a value object, designing it to be immutable.&lt;/li&gt;
  &lt;li&gt;In the case of collections, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadOnlyCollection&lt;/code&gt; when they must keep their size.&lt;/li&gt;
  &lt;li&gt;If the object can’t be immutable by design but you need to avoid state changes at all cost, cloning the object by returning a deep copy of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We may be tempted to clone objects every time someone asks for a reference to them. However this may not be possible (like with the EventBus) or it may be too expensive and complex. I’d say that cloning is the last alternative and perhaps the need for it is a design smell. Who is responsible for ensuring that object references are not causing memory leaks? It boils down to the &lt;a href=&quot;http://wiki.c2.com/?PrincipleOfLeastAstonishment&quot;&gt;principle of Least Astonishment&lt;/a&gt;. We should design interfaces (methods) in such a way that it’s obvious how references and state are going to be managed. If it looks like the consumer (the one asking for the reference) will not be aware of it and the consumer will likely make undesired changes to the object, then cloning the object could be a good defensive approach. But I would rather try to think how to make the API more expressive considering context and level of abstraction. I assume that the caller understands how references work.&lt;/p&gt;

&lt;p&gt;If you, dear reader, provide some code examples I will be able to clarify my point with code. I’ll update this post if I come up with some snippets.&lt;/p&gt;
</description>
          <pubDate>2015-10-16T09:34:38+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/10/object-references-state-and-side-effects</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/10/object-references-state-and-side-effects</guid>
        </item>
      
    
      
        <item>
          <title>Refactorizando con Streams</title>
          <description>&lt;p&gt;Hoy traigo una serie de ejemplos de refactorización a modo de introducción a las nuevas características funcionales de Java 8. Así que, si tenías curiosidad y no te habías atrevido a experimentar con ellas, ¡te animo a que pruebes!&lt;/p&gt;

&lt;p&gt;Empezamos definiendo una clase &lt;em&gt;Person&lt;/em&gt; básica con un nombre y una edad:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/344e58dfff22f2d16aefc42164497b75.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Una vez definida nuestra clase base, vamos a hacer un ejemplo sencillo: tenemos una lista de personas y queremos tener otra lista pero &lt;strong&gt;sólo&lt;/strong&gt; con las personas que sean &lt;strong&gt;mayores de 22 años&lt;/strong&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/fb5a3686398d3ff9e9227156f9483243.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Y ahora usando Java 8:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/829395eb3f436c05b8f17cbaae7e3ae1.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Vamos a explicarlo un poco. Primero tenemos el método &lt;strong&gt;&lt;em&gt;stream()&lt;/em&gt;&lt;/strong&gt;, propio de las colecciones, que devuelve un &lt;em&gt;&lt;strong&gt;Stream&lt;/strong&gt;&lt;/em&gt; (conjunto inmutable de elementos y una serie de funciones con las que operar sobre el mismo). Seguimos con la función &lt;strong&gt;&lt;em&gt;filter&lt;/em&gt;&lt;/strong&gt; que, como su nombre indica, filtra los elementos a partir de un &lt;strong&gt;predicado&lt;/strong&gt; (función que evalúa un argumento siendo el resultado &lt;em&gt;verdadero&lt;/em&gt; o &lt;em&gt;falso).&lt;/em&gt; Y por último_,_ tenemos que volver a transformar el &lt;em&gt;stream&lt;/em&gt; en una lista, por lo que llamamos a la función &lt;strong&gt;&lt;em&gt;collect&lt;/em&gt;&lt;/strong&gt; y nos ayudamos de los &lt;em&gt;&lt;strong&gt;Collectors&lt;/strong&gt;&lt;/em&gt; para ello.&lt;/p&gt;

&lt;p&gt;Podemos extraer el predicado en una variable para tener una mejor legibilidad:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/ca04c573d4160ff0b2362f69c68eaeeb.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Ahora pongamos otro ejemplo. Seguimos teniendo la misma lista de personas pero ahora queremos un &lt;strong&gt;String&lt;/strong&gt; que contenga los &lt;strong&gt;nombres&lt;/strong&gt; de las personas que sean &lt;strong&gt;menores de 22 años&lt;/strong&gt; separados por &lt;strong&gt;”, “&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Java 7:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/7c73cbb487ff2f03ebdaa90776fe37ef.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Java 8:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/JoseDeniz/fc9c7fb1309607d9dfb33dc6d149331a.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;En este ejemplo, vemos varias cosas nuevas como la función &lt;em&gt;&lt;strong&gt;map&lt;/strong&gt;&lt;/em&gt;, que devuelve un nuevo &lt;em&gt;Stream&lt;/em&gt; del mismo tamaño, pero con la diferencia que cada elemento es el resultado de aplicar la función pasada por parámetro sobre cada uno de ellos (en este caso, me devuelve un &lt;em&gt;Stream&amp;lt;String&amp;gt;&lt;/em&gt;. Además, vemos como podemos sustituir nuestra función &lt;em&gt;lambda&lt;/em&gt; por una referencia al método, es  decir, hemos sustituído:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;person -&amp;gt; person.name() por Person::name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ya que queda más compacto y fácil de leer. Y por último, unimos todos los nombres separados por &lt;strong&gt;”, “&lt;/strong&gt; sin tener que estar preocupándonos en si se nos añade o no una &lt;strong&gt;”, “&lt;/strong&gt; de más.&lt;/p&gt;

&lt;p&gt;A modo de conclusión, me gusta más ésta forma de programar declarativamente, ya que mejora mucho la legibilidad del código e incluso es más fácil de mantener. Ya vimos por ejemplo que, para reducir la lista de personas a una lista de nombres, bastó con añadir una línea llamando a la función &lt;em&gt;map&lt;/em&gt; y listo.&lt;/p&gt;
</description>
          <pubDate>2015-10-08T18:50:52+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/10/refactorizando-con-streams</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/10/refactorizando-con-streams</guid>
        </item>
      
    
      
        <item>
          <title>XP Team Building</title>
          <description>&lt;h2 id=&quot;let-the-team-walk-its-path&quot;&gt;Let the team walk its path&lt;/h2&gt;

&lt;p&gt;Every team walks at its own pace and I haven’t found a way to speed it up myself, I don’t think there is one regardless of whether you are an external coach or a regular member of the team. Trying to push the team will screw up the work environment, the pressure may introduce interpersonal conflicts and severe damages in the quality of the product. I mean, people will do stuff they do know it’s wrong because of the sense of emergency. On the other hand trying to pull the team away will give its members the impression that they are not trusted professionals, again causing problems among people and discouraging them from being proactive and willing to learn.&lt;/p&gt;

&lt;p&gt;The only way we can help the team progress is to help them walk their own path, removing impediments along the way, answering questions when asked to do so.&lt;/p&gt;

&lt;p&gt;I’ve learned that it’s not possible to develop a software product at the speed that I’d like whilst mentoring people. I have to choose either to be a trainer or to be a developer but not both things at the same time because the goals are different. When working as a trainer the goal is that people learn effectively and the best way, for us humans, to learn is by making mistakes that let us learn from ourselves. As a mentor I must combine small theoretical explanations, recommendations and practical examples with time for people to practice and to make their own decisions. They must have the chance to fail and discover. If they don’t recognize the failure my mission is to provide feedback and explain why is this or that a mistake and what are the consequences. Deep lessons are learned with pain - success is fantastic but it doesn’t teach. However this style of mentoring takes a lot of time, it’s probably the top most time consuming way. It’s a company wide commitment, an effort for everyone.&lt;/p&gt;

&lt;p&gt;Often companies ask us to join them for a new project that must deliver value within a tight schedule and at the same time they want to build up a team of XP developers with people that have never been exposed to XP. I must say this is completely impossible in my experience. If the quality of the product needs to be excellent and deadlines are tight, the best thing the company can do is to hire a seasoned high-performing XP team whose members have been working together for years. On the other hand, if the actual goal is to build up a team, this is an investment that lasts several years. According to my experience, a group of 6 to 8 developers become an XP team after 2 years of training, guidance, reviews and practice. It requires several training courses during the various stages of the transition, practical examples, guidance and moreover it requires small failures (hopefully reversible ones). People have to have the margin to fail and learn from their mistakes. During this period some people will very likely leave the company and some new people will join.&lt;/p&gt;

&lt;p&gt;I know the word quality is too abstract, we don’t have a definition for what quality is but I am actually talking about well-known maintenance issues. A common mistake beginners make is to write brittle and hard to maintain tests that with time impede developers changing or adding features. Those tests are eventually deleted. It’s waste unless you consider this to be another stage in the team’s learning curve.&lt;/p&gt;

&lt;p&gt;Nobody writes perfect code anyway, every team makes mistakes so the point is not to aim for perfection. The point is to avoid or minimize the amount of things we do know are waste, basically because we have failed in the past.&lt;/p&gt;

&lt;p&gt;Hiring seasoned external consultants means they won’t make the same mistakes they did in the past although they’ll make new mistakes. Every team is different as well as every project.&lt;/p&gt;

&lt;p&gt;As a consultant I won’t prevent the team from making mistakes when the goal is to train them, instead I’ll try to keep the cycles small enough so that mistakes can be fixed soon and cheap. But it’s up to the team to ask for feedback and review, my job is not to control the source code - it’s to support the team!&lt;/p&gt;

&lt;p&gt;In some situations it could be beneficial that a small group of experts write the “walking skeleton” with the first group of product features in order to define architecture, style and conventions that others can follow. It serves to explore risks and exposes an example that others can follow. There are several perils of this approach though. I’d be careful with it - sorry don’t feel like writing about these drawbacks now.&lt;/p&gt;
</description>
          <pubDate>2015-09-24T16:15:51+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/09/xp-team-building</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/09/xp-team-building</guid>
        </item>
      
    
      
        <item>
          <title>ES6 + browserify + babel + gulp + jasmine</title>
          <description>&lt;p&gt;During Socrates Conference 2015 we decided that it’s the right time to jump in &lt;a href=&quot;http://es6-features.org/#Constants&quot;&gt;ES6&lt;/a&gt; to develop a green field project that our customer is starting. Given that &lt;strong&gt;ES6&lt;/strong&gt; is already the stable and latest version of &lt;em&gt;JavaScript&lt;/em&gt;, it does not make any sense to start a new project with &lt;strong&gt;ES5&lt;/strong&gt;, an already old version of the language. With the kind of functional style that we use when coding in JavaScript, the changes are not too big anyway as we are not going to use classes anyway. But we can gain a lot of value from using block scope with &lt;strong&gt;let&lt;/strong&gt; and &lt;strong&gt;const&lt;/strong&gt;, and avoiding the use of &lt;strong&gt;var&lt;/strong&gt; from now on. Configuring the tools has taken more time than I thought as the &lt;strong&gt;tooling and the ecosystem is changing really fast&lt;/strong&gt;. You read a recipe from a blog post which is 6 months old and it turns out that most of the stuff described is no longer working. Some &lt;em&gt;npm&lt;/em&gt; packages don’t work anymore or the behavior at some point is very different from a previous version… apparently things are even more obscure on &lt;em&gt;Windows&lt;/em&gt; which is the platform we have to use for this project.&lt;/p&gt;

&lt;p&gt;As an example, I installed &lt;em&gt;karma&lt;/em&gt; via &lt;em&gt;npm&lt;/em&gt; the latest version. But when running &lt;em&gt;gulp&lt;/em&gt; from the command line it stopped working with no error message at all, just a line break and back to the prompt. I commented all the lines in the &lt;em&gt;gulpfile.js&lt;/em&gt; and then uncommented lines one by one executing gulp each time to discover that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require(&apos;karma&apos;)&lt;/code&gt; was the reason. So I got into the &lt;em&gt;*node repl&lt;/em&gt; and type this myself:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;var k = require(‘karma’)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The result was the same, the &lt;em&gt;node repl&lt;/em&gt; &lt;strong&gt;exited silently&lt;/strong&gt; getting me back to the command line prompt. I couldn’t find a single way to catch the error although I tried try-catch, signal capturing, domains… and none of that worked. Then I started downgrading the version of the &lt;em&gt;karma&lt;/em&gt; package until it worked for me. Version 0.13.3 works but 0.13.4 doesn’t. It must be a very specific problem on my machine but I couldn’t find any other solution. Eventually we are not using &lt;em&gt;karma&lt;/em&gt; for now, we are using &lt;em&gt;jasmine&lt;/em&gt; stand alone version and &lt;em&gt;mocha&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is the simplest &lt;em&gt;gulpfile&lt;/em&gt; I was able to get working:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/21a033400d2cf5379b464153b4dd9670.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The generated package is &lt;em&gt;all.js&lt;/em&gt; which I include in the html page. The application’s entry point is on &lt;em&gt;main.js&lt;/em&gt; with exposes a function called &lt;em&gt;startApp&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;App starts up at the bottom of the html page:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/21227f4f28f21e72111cec45988ec783.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;em&gt;main.js&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/820a8207e14631d91b9377f1b2822b5c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;In order to run the tests the most simple choice was &lt;em&gt;Jasmine&lt;/em&gt; stand alone, including the generated &lt;em&gt;specs.js&lt;/em&gt; file in the &lt;em&gt;SpecRunner.html&lt;/em&gt; page. As the tests include the production code, the generated file &lt;em&gt;specs.js&lt;/em&gt; already include all the production code.&lt;/p&gt;

&lt;p&gt;tests:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d27b4462d4641a7bdf0ffcaa913eaf5c.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The next step was to include &lt;em&gt;watchify&lt;/em&gt; in order to rebundle everytime a file is saved.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;gulpfile.js&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/bd4e4736382124a3c55b0742480742b2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;This post was written on September 14th 2015, if you try to use any of the snippets posted a few months later they probably won’t work for you. These are the versions used:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;package.json&lt;/em&gt;:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/0dd4831b06032037ec8c41222b960a3c.js&quot;&gt;&lt;/script&gt;

</description>
          <pubDate>2015-09-14T09:09:58+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/09/es6-browserify-babel-gulp-jasmine</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/09/es6-browserify-babel-gulp-jasmine</guid>
        </item>
      
    
      
        <item>
          <title>Las ventajas de usar parámetros y variables tipados en PowerShell</title>
          <description>&lt;p&gt;Cuanto más uso PowerShell más convencido estoy de lo importante que es tipar las variables y los parámetros de las funciones. Debido a la forma en que trabaja PowerShell, especificar los tipos me ayuda a evitar comportamientos indeseados.&lt;/p&gt;

&lt;p&gt;Por ejemplo, dado este script:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2

$items = Get-ChildItem
if ($items) {
   $items.Count
}
&lt;/pre&gt;

&lt;p&gt;Si lo ejecuto estando en un directorio con varios archivos o carpetas, mostrará en pantalla el número de items. Pero si lo ejecuto en un directorio que tenga únicamente un ítem, el resultado será un error estrepitoso porque dice que no tiene ni idea de qué es eso de la propiedad &lt;em&gt;Count&lt;/em&gt;. Simplemente con tipar la variable &lt;em&gt;$items&lt;/em&gt; este ejemplo funcionaría perfectamente:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2

[array]$items = Get-ChildItem
if ($items) {
   $items.Count
}
&lt;/pre&gt;

&lt;p&gt;Otro ejemplo habitual  me lo encuentro cuando tengo una función en la que recibo la ruta de un directorio. Es muy habitual recibir un string con la ruta. El problema es que si trabajamos con rutas de red, esto no funciona muy bien y hay que añadirle por delante de la ruta la cadena “filesystem::”. A no ser que estemos interactuando con código .Net, en cuyo caso la ruta con el “filesystem::” por delante no le gusta ni un pelo. Al final es mucho más sencillo si hago el parámetro tipado con el tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.IO.DirectoryInfo&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileInfo&lt;/code&gt; o el que sea pertinente.&lt;/p&gt;
</description>
          <pubDate>2015-08-18T09:52:05+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/08/powershell-las-ventajas-de-usar-parametros-y-variables-tipados</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/08/powershell-las-ventajas-de-usar-parametros-y-variables-tipados</guid>
        </item>
      
    
      
        <item>
          <title>Switch parameters en PowerShell</title>
          <description>&lt;p&gt;En PowerShell es muy común usar parámetros de tipo &lt;em&gt;switch&lt;/em&gt;. La peculiaridad de estos parámetros es que al usarlos, se especifica el nombre del parámetro pero no se proporciona ningún valor, ya que se asume que al usarlo su valor será &lt;em&gt;$true&lt;/em&gt; y &lt;em&gt;$false&lt;/em&gt; si no se especifica. Ejemplos típicos son el uso de –_Recurse o -Force. _&lt;/p&gt;

&lt;p&gt;Este sería un ejemplo de con este tipo de parámetros:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Function Do-Something([Switch]$Recurse) {
    Write-Host $Recurse
}

Do-Something -Recurse
Do-Something
&lt;/pre&gt;

&lt;p&gt;Si ejecuto este script, veré por pantalla &lt;em&gt;$True&lt;/em&gt; y &lt;em&gt;$False, como podría esperar. Si le añado algunas modificaciones al código, el resultado sigue siendo el esperado:&lt;/em&gt;&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Function Do-Something([Switch]$Recurse) {
    if ($Recurse.IsPresent) { 
        Write-Host &quot;Lo haré recursivo&quot;
    } Else {
        Write-Host &quot;No lo haré recursivo&quot;
    }
}

Do-Something -Recurse
Do-Something
&lt;/pre&gt;

&lt;p&gt;Hasta aquí todo bien, pero en realidad no lo he estado haciendo como está recomendado. Si me diese por hacer una prueba en Pester en la que me viese obligado a verificar el &lt;em&gt;$Recurse&lt;/em&gt; de este modo:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;$Recurse | Should Be $True
&lt;/pre&gt;

&lt;p&gt;Obtendría un resultado inesperado, ya que en realidad &lt;em&gt;$Recurse&lt;/em&gt; no es de tipo Boolean. Al hacer un GetType() es posible ver que en realidad es de tipo &lt;em&gt;System.Management.Automation.SwitchParameter&lt;/em&gt;. En realidad la forma correcta de verificar si me han pasado el parámetro es así:&lt;/p&gt;

&lt;pre class=&quot;lang:default decode:true &quot;&gt;$Recurse.IsPresent | Should Be $True&lt;/pre&gt;

&lt;p&gt;Y si alguna vez es necesario tratarlo como un boolean, siempre es posible recurrir al método &lt;em&gt;ToBool()&lt;/em&gt;.&lt;/p&gt;
</description>
          <pubDate>2015-08-17T22:37:14+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/08/powershell-switch-parameters</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/08/powershell-switch-parameters</guid>
        </item>
      
    
      
        <item>
          <title>Using C# Collections</title>
          <description>&lt;p&gt;There are many ways to work with collections. We are following &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/dn169389(v=vs.110).aspx&quot;&gt;Microsoft Guidelines for Collections&lt;/a&gt; plus some ideas that &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; explains in &lt;a href=&quot;http://www.amazon.com/Implementation-Patterns-Kent-Beck/dp/0321413091&quot;&gt;Implementation Patterns&lt;/a&gt;. I’ve created a &lt;a href=&quot;https://bitbucket.org/carlosble/collections&quot;&gt;repository with code examples&lt;/a&gt; so that anyone can play with them. All the unit tests in the project are green except for two, which are red on purpose to express my surprise when I wrote them, because it’s a behavior I didn’t expect.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; is not dangerous itself, the surprise may come up when the variable is created via a &lt;strong&gt;LINQ&lt;/strong&gt; expression (&lt;em&gt;.Select&lt;/em&gt;, &lt;em&gt;.Where …&lt;/em&gt;). Then it may be the case that the &lt;strong&gt;query execution is deferred&lt;/strong&gt; and the &lt;strong&gt;behavior&lt;/strong&gt; of the code is totally &lt;strong&gt;unexpected&lt;/strong&gt;. For this reason we try to &lt;strong&gt;avoid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IQueryable&amp;lt;T&amp;gt;&lt;/code&gt; as the return type&lt;/strong&gt; of functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try not to expose collections as much as you can by wrapping them&lt;/strong&gt; within objects you own which expose only the minimum domain required features. &lt;strong&gt;But if you have to&lt;/strong&gt; expose the collection anyway, in our team the convention is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadOnlyCollection&amp;lt;T&amp;gt;&lt;/code&gt; is the type returned to avoid modifications to the number of elements in the collection. (&lt;em&gt;Internally it’s just a wrapper around IList&lt;/em&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IList&amp;lt;T&amp;gt;&lt;/code&gt; is returned when the collection may be modified and the order of the items in the collection is relevant.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICollection&amp;lt;T&amp;gt;&lt;/code&gt; is returned when the collection may be modified and we don’t care about the order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good code expresses the programmer’s intent, this is why we choose from the three types above to return collections when we have to.&lt;/p&gt;

&lt;p&gt;When it comes to parameters, it’s &lt;strong&gt;OK to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; as a parameter&lt;/strong&gt; because it’s the most generic collection type. Although the caller could send an unresolved Linq query as an argument hidden in the form of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;, the method &lt;strong&gt;does not have to be defensive&lt;/strong&gt; about it (in most cases).&lt;/p&gt;

&lt;p&gt;Other built-in collections like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; are intended to be used &lt;strong&gt;internally, only for implementation&lt;/strong&gt;. So it’s OK for a private method to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;. The type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Collection&amp;lt;T&amp;gt;&lt;/code&gt; actually implements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IList&amp;lt;T&amp;gt;&lt;/code&gt; so I can’t find a good reason right now to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Collection&amp;lt;T&amp;gt;&lt;/code&gt; instead of just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;
</description>
          <pubDate>2015-08-12T17:41:16+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/08/using-c-collections</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/08/using-c-collections</guid>
        </item>
      
    
      
        <item>
          <title>Cuidado que ($a -eq $a) no siempre es $true</title>
          <description>&lt;p&gt;Este es uno de esos ejemplos en los que es importante intentar documentarse todo lo posible al desarrollar en un lenguaje/plataforma que no conocemos. Es frecuente asumir conceptos basados en nuestros conocimientos previos de otros lenguajes, pero en ocasiones nos puede jugar malas pasadas. En este caso voy a mostrar un ejemplo muy sencillo en el que yo asumí erróneamente el funcionamiento de algo tan sencillo como un operador de comparación.&lt;/p&gt;

&lt;p&gt;Este problema lo encontré desarrollando una prueba mientras practicaba TDD. Por hacerlo fácil, este es el ejemplo más simple que se me ocurre para describir lo equivocado que estaba:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;$a = @(&quot;item1&quot;, &quot;item2&quot;)
if ($a -eq $a) { Write-Host &quot;$a es igual que $a&quot; }
else { Write-Host &quot;$a no es igual que $a&quot; }&lt;/pre&gt;

&lt;p&gt;Asumiendo que &lt;strong&gt;-eq&lt;/strong&gt; es el operador de igualdad, alguien que no conozca PowerShell pero si conozca otros lenguajes de programación podría asumir que este script de ejemplo entraría por el if en lugar de por el else. Mi error fue precisamente ese. Si ejecuto este script en powershell, pintará en pantalla &lt;em&gt;&lt;strong&gt;“item1 item2 no es igual que item1 item2”&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Si me hubiera molestado en leer la &lt;a href=&quot;https://technet.microsoft.com/en-us/library/hh847759.aspx&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt; de PowerShell hubiera visto que el operador &lt;strong&gt;-eq&lt;/strong&gt; es bastante peculiar y en realidad hace algo más complicado. Aunque recomiendo leer la fuente original, estes es un pequeño resumen:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Si ambas variables son de tipo string, aplicará una comparación “case-insensitive” retornando $true o $false&lt;/li&gt;
  &lt;li&gt;Si la de la izquierda es un array de strings @(“item1”, “item2”) y la de la derecha es un string “item1”, buscará si el array contiene “item1” y retornará @(“item1”)&lt;/li&gt;
  &lt;li&gt;Si a la izquierda tenemos un array de strings @(“item1”, “item2”) y a la derecha un array de strings con un único item @(“item1”), retornará @(“item1”)&lt;/li&gt;
  &lt;li&gt;Como ya hemos visto al principio, si tenemos un dos arrays de strings, aunque sean iguales, retornará @()&lt;/li&gt;
  &lt;li&gt;Algunos ejemplos anteriores darán resultados distintos si invertimos las variables y cambiamos izquierda por derecha, si quieres saberlos, prueba! 😉&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conclusión, hay que leer más. Para mi es de mucha ayuda leer código de otros. Estudiar cómo están desarrollados &lt;a href=&quot;https://github.com/pester/Pester&quot;&gt;Pester&lt;/a&gt; o &lt;a href=&quot;https://github.com/psake/psake&quot;&gt;Psake&lt;/a&gt; me ha permitido entender mucho mejor las bondades de PowerShell.&lt;/p&gt;
</description>
          <pubDate>2015-08-07T00:22:46+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/08/powershell-cuidado-que-a-eq-a-no-siempre-es-true</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/08/powershell-cuidado-que-a-eq-a-no-siempre-es-true</guid>
        </item>
      
    
      
        <item>
          <title>La importancia del Set-StrictMode</title>
          <description>&lt;p&gt;Cuando empecé a programar scripts en PowerShell, cometía muchísimos fallos fruto de mi intoxicación con otros lenguajes, especialmente C#, con el que trabajo habitualmente. Después de un tiempo, me di cuenta que PowerShell tiene muchas más similitudes con JavaScript que con C# ya que es un lenguaje interpretado y de tipado débil. Y un tiempo después, aprendí que podía programar en PowerShell de una manera más próxima a TypeScript.&lt;/p&gt;

&lt;p&gt;Lo explico de esta forma porque a mi cerebro le resulta más sencillo recurrir a este paralelismo. Cuando estoy programando en PowerShell, a mi cerebro le cuesta mucho menos si llevo puesto el sombrero de programador en TypeScript/Javascript) que si estoy pensando en C#. Cometo menos errores y el código me sale de forma más fluida.&lt;/p&gt;

&lt;p&gt;Aún así hay un cmdlet que me ayuda muchísimo y que creo que permite generar un código mucho más robusto. Se trata del cmdlet &lt;strong&gt;Set-StrictMode&lt;/strong&gt;. Este cmdlet permite establecer una serie de restricciones de cara al código que escribimos en PowerShell. Generalmente siempre añado esta línea al principio de mis scripts:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2&lt;/pre&gt;

&lt;p&gt;La versión 2 determina exactamente qué restricciones se van a aplicar. Las opciones son 1, 2 o Latest. Resumiendo lo que explican en la &lt;a href=&quot;https://technet.microsoft.com/es-es/library/hh849692.aspx&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt; de Microsoft:&lt;/p&gt;

&lt;p&gt;1.0 – Prohíbe referencias a variables no inicializadas.&lt;/p&gt;

&lt;p&gt;2.0 – Prohíbe:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Referencias a variables no inicializadas&lt;/li&gt;
  &lt;li&gt;Referencias a propiedades de un objeto que no existen.&lt;/li&gt;
  &lt;li&gt;Llamadas a fuciones utilizando la sintaxis de llamadas a métodos (usando los parñentesis)&lt;/li&gt;
  &lt;li&gt;El uso de variables sin nombre (${})&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Latest – Aplica la versión más estricta de las disponibles. Dependerá de la versión de PowerShell que se esté utilizando, pero a día de hoy (PowerShell 5.0) el valor más alto sigue siendo 2.&lt;/p&gt;

&lt;p&gt;Aunque la tentación puede ser recurrir al parámetro &lt;strong&gt;Latest&lt;/strong&gt;, no lo recomiendo ya que podría implicar que se rompan scripts que funcionan bien si se incrementa el nivel de restricciones en una futura versión de PowerShell.&lt;/p&gt;

&lt;p&gt;Dicho todo esto, qué mejor que un ejemplo:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;function Suma($valor1, $valor2) {
    return $valr1 + $valor2
}

$resultado = Suma(1, 2)
Write-Host $resultado&lt;/pre&gt;

&lt;p&gt;Si ejecuto este script con &lt;strong&gt;Set-StrictMode -Off&lt;/strong&gt; el resutado será que no se pinta nada en pantalla. La razón es que me se hace referencia a la variable &lt;em&gt;$valr1&lt;/em&gt; en lugar de a &lt;em&gt;$valor1&lt;/em&gt;. Si corrijo este fallo, aún así obtendré un resultado indeseado, ya que en pantalla se pintará “1 2” sin las comillas. En este caso es un error típico cuando tengo puesto el sombrero de C#, el error es que estoy llamando a la función &lt;em&gt;Suma&lt;/em&gt; como si fuese un método. Para que el script funcionase como deseo, debería ser así:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2

function Suma($valor1, $valor2) {
    return $valor1 + $valor2
}

$resultado = Suma 1 2
Write-Host $resultado&lt;/pre&gt;

&lt;h1 id=&quot;sus-similitudes-con-typescript&quot;&gt;Sus similitudes con TypeScript&lt;/h1&gt;

&lt;p&gt;Al principio del post he mencionado que con el tiempo me he acostumbrado a la proximidad con TypeScript. Salvando las distancias, este podría ser una muestra basada en el ejemplo anterior:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2

function Suma([int]$valor1, [int]$valor2) { 
   return $valor1 + $valor2 
}

$resultado = Suma 1 2
Write-Host $resultado&lt;/pre&gt;

&lt;p&gt;Incluso podría retorcerlo un poco más y ponerme más estricto:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Set-StrictMode -Version 2

function Suma {
     Param(
       [Parameter(Mandatory=$true)][int]$valor1,
       [Parameter(Mandatory=$true)][int]$valor2
    )
    return $valor1 + $valor2
}

$resultado = Suma (1, 2)
Write-Host $resultado
&lt;/pre&gt;

&lt;p&gt;Normalmente no llego tan lejos ya que creo que dificulta demasiado la lectura del código y, en la mayoría de los casos, no necesito recurrir a tantas restricciones en el código.&lt;/p&gt;

&lt;p&gt;Además de recurrir al &lt;strong&gt;Set-StrictMode&lt;/strong&gt;, aplico TDD para desarrollar mis scripts, algo que también resulta de muchísima ayuda, especialmente cuando empiezas a manejar mucho código. Pero lo explicaré en otro post.&lt;/p&gt;
</description>
          <pubDate>2015-08-03T23:50:39+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/08/powershell-la-importancia-del-set-strictmode</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/08/powershell-la-importancia-del-set-strictmode</guid>
        </item>
      
    
      
        <item>
          <title>Remove data structures noise from your tests with builders</title>
          <description>&lt;p&gt;Among other qualities good tests should be easy to read, quick to understand. 
When the test requires complex data structures to be sent to the SUT or to be part of a stubbed answer, it takes longer to read.
Moreover those structures use to evolve as the production code does causing too many changes in the tests in order to adapt them. An indirection level in between the test and the production code helps improve readability and ease of maintenance. Builders come to the rescue. I often overload builder methods to support several data structures and then apply the conversions internally.&lt;/p&gt;

&lt;p&gt;As an example, this is the setup of one of our tests before the final refactor:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d3685b3adb051a898b4fbe6861a29dfd.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Imagine how ugly those tests were before writing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACatalog&lt;/code&gt; builder. And this is the test after the builder was overloaded to supply a more comfortable API:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/f0d0d015a9cb3a5ffa33ca1b20b0a8ad.js&quot;&gt;&lt;/script&gt;

</description>
          <pubDate>2015-07-23T08:22:15+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/07/remove-data-structures-noise-from-your-tests-with-builders</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/07/remove-data-structures-noise-from-your-tests-with-builders</guid>
        </item>
      
    
      
        <item>
          <title>Productive Pair Programming</title>
          <description>&lt;p&gt;The title of this post is redundant, &lt;strong&gt;pair programming is&lt;/strong&gt; already a &lt;strong&gt;productivity technique&lt;/strong&gt;. That’s my understanding or pair programming not just two people sitting together. Two people may code together for learning or mentoring purposes, however we pair for productivity reasons - productivity in the &lt;strong&gt;long term&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Like any other XP practice, this one aims to promote the values:&lt;/p&gt;

&lt;p&gt;When I pair I get immediate &lt;strong&gt;feedback&lt;/strong&gt; about my design and ideas. The &lt;strong&gt;communication&lt;/strong&gt; is direct and the conversation provides us with &lt;strong&gt;simplicity&lt;/strong&gt;. Good pairs &lt;strong&gt;respect&lt;/strong&gt; each other and have the &lt;strong&gt;courage&lt;/strong&gt; to split when necessary.&lt;/p&gt;

&lt;p&gt;In my experience, it takes quite a lot of time to become a productive pair because one needs to &lt;strong&gt;learn how the other think&lt;/strong&gt;. You need to know when the other person is focused &lt;strong&gt;not to break her flow&lt;/strong&gt;. The navigator should never perform the role of the IDE, we obviously don’t interrupt to say… &lt;em&gt;“you missed a bracket in there”&lt;/em&gt; as the IDE is already highlighting the mistake. We wait until the driver is not typing to ask questions, propose changes or take turns. Nevertheless &lt;strong&gt;waiting for&lt;/strong&gt; the &lt;strong&gt;silence&lt;/strong&gt; in order to &lt;strong&gt;start up a discussion is not enough&lt;/strong&gt;. When I am the driver, I need my pair to realise that sometimes I need silence to think, specially when my &lt;strong&gt;flow&lt;/strong&gt; is appropriate. The fact that I am not typing does not mean I am ready to talk about other levels of abstraction. As the driver, when this happens I &lt;strong&gt;ask the navigator for a few seconds of patience and trust&lt;/strong&gt;. Flow is one of the most important principles when it comes to TDD and Pair Programming to me. &lt;strong&gt;If the flow is interrupted continuously, pairing is frustrating&lt;/strong&gt;. As a navigator part of my mission is to discover when the driver is ready to listen to me. Although a healthy pair is talkative, silence is necessary. The amount of silence depends on the context. If the navigator &lt;a href=&quot;http://codurance.com/2015/06/17/finding-the-biting-point/&quot;&gt;is a junior&lt;/a&gt; (means that he lacks some knowledge - domain or technical) then as a driver I need more time to demonstrate my points. I need to conquer little milestones with code to later explain the underlying rationale with words. In this case, talking about written code that works, feels easier to me.&lt;/p&gt;

&lt;p&gt;I’ve learned recently that sometimes I just need to ask the navigator to be quite and write down notes that we can discuss some minutes later. Although I used to be open to discussion at anytime, I’ve learned to prioritize flow. If the navigator is a senior then his comments will be practical and direct and so continuous discussion feels more natural.&lt;/p&gt;

&lt;p&gt;The silent moments I am talking about last between &lt;strong&gt;30 seconds&lt;/strong&gt; and 3 minutes. Being quite for more than 5 minutes might be a sign that the pair is not working well. So yes, there is a &lt;strong&gt;conversation&lt;/strong&gt; which &lt;strong&gt;is not the same as thinking out loud&lt;/strong&gt;. My recommendation is that the navigator always has some &lt;strong&gt;paper notes&lt;/strong&gt; to avoid thinking out loud half baked ideas. Discussing half baked ideas is OK as long as the driver is not typing. If I am typing I can’t listen to my pair.&lt;/p&gt;

&lt;p&gt;Pairing is also about &lt;strong&gt;adding the right amount of pressure&lt;/strong&gt; to the other. The driver should engage the navigator to avoid the “back-seat” driver syndrome. Taking turns help. Alternate often when the pair is well-balanced. Consider taking longer turns when there is a junior. Be careful, if the pressure trespass a certain threshold part of the intellectual capacity is cancelled. We can’t think properly under high pressure.&lt;/p&gt;

&lt;p&gt;There are different kinds of &lt;strong&gt;interruptions&lt;/strong&gt; from the point of view of the &lt;strong&gt;abstraction level&lt;/strong&gt;. Low level abstraction comments are easier to handle than high level ones. For instance, say the driver has stopped typing and she is observing the code she’s just written, the navigator could say…. &lt;em&gt;“that method should be private, rather public”&lt;/em&gt;. The level of abstraction of that comment is very likely compatible with the current thoughts of the driver, she can easily accept the change and still focus on the TO-DO list. However, something like &lt;em&gt;“how would you implement that in Clojure”&lt;/em&gt; might kill the flow. That comment is OK once the driver is open to discuss. Having a &lt;strong&gt;TO-DO list or&lt;/strong&gt; some kind of little &lt;strong&gt;roadmap&lt;/strong&gt; that is created at the beginning of the pairing session is important to focus on the right level of abstraction.&lt;/p&gt;

&lt;p&gt;There is a lot to write on pair programming, this post contains just a few ideas related to my recent experiences. I like &lt;a href=&quot;http://agilefocus.com/2009/01/06/21-ways-to-hate-pair-programming/&quot;&gt;this funny list of ways to hate pair programming&lt;/a&gt; - the &lt;strong&gt;challenge&lt;/strong&gt; lies in getting to &lt;strong&gt;know your pair enough&lt;/strong&gt; to notice when you are pairing badly.&lt;/p&gt;
</description>
          <pubDate>2015-06-30T23:20:46+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/06/productive-pair-programming</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/06/productive-pair-programming</guid>
        </item>
      
    
      
        <item>
          <title>Interrumpir la ejecución cuando Import-Module no encuentra el módulo</title>
          <description>&lt;p&gt;Esto es un truco sencillo y muy básico de PowerShell, pero puede desconcertar bastante a quien está empezando o utiliza PowerShell de forma esporádica.&lt;/p&gt;

&lt;p&gt;En PowerShell existen los llamados “terminating errors” y los “non-terminating errors”. Como su nombre permite intuir, unos finalizan la ejecución del script en curso cuando se producen y los otros no, limitándose a informar del error. Hasta aquí he descrito el comportamiento por defecto. Que un error sea del tipo “terminating” o del tipo “non-terminating”, no es algo que nosotros podamos controlar, y eso puede dar algún que otro quebradero de cabeza en algunas ocasiones.&lt;/p&gt;

&lt;p&gt;Hoy estaba trabajando con un script en el que hacía un Import-Module y luego ejecutaba otra serie de scripts, algunos relacionados con el módulo que trataba de importar y otros no. Por simplificar, imaginemos que tenía un código como este:&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;Import-Module NombreDeModuloQueNoExiste
Write-Host &quot;Aquí ejecutaría código NO relacionado con el módulo&quot;
Write-Host &quot;Aquí ejecutaría código relacionado con el módulo&quot;&lt;/pre&gt;

&lt;p&gt;En este caso el módulo que estaba intentando importar resulta que no existía en mi máquina, por lo que al intentar hacer un Import-Module, obtenía un error que me indicaba que el módulo no se encontraba. El problema es que el comportamiento de PowerShell no era exáctamente como yo quería:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Error-Import-Module.png&quot; alt=&quot;Error-Import-Module&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Como se puede ver, el resultado era que me salía el error, pero además se estaba ejecutando las dos líneas de código posteriores, y ese no era el comportamiento que yo quería. Como no estoy todo el día con PowerShell, a veces me pasan este tipo de cosas y me desorientan un poco, pero en este caso me acordaba de este tipo de problemas y lo pude atajar rápido.&lt;/p&gt;

&lt;p&gt;Resulta que PowerShell tiene una variable llamada &lt;strong&gt;$ErrorActionPreference&lt;/strong&gt; que determina el comportamiento a seguir en caso de errores “non-terminating”. El valor por defecto es &lt;strong&gt;Continue&lt;/strong&gt; así que es algo así como el &lt;strong&gt;On Error Resume Next&lt;/strong&gt; de Visual Basic.&lt;/p&gt;

&lt;p&gt;Los valores posibles para esta variable son Stop, Inquire, Continue, Suspend y SilentlyContinue, pero yo normalmente únicamente utilizo los valores &lt;strong&gt;Stop&lt;/strong&gt; y &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;De este modo, estableciendo la variable antes de ejecutar el &lt;strong&gt;Import-Module,&lt;/strong&gt; es posible obtener el comportamiento deseado.&lt;/p&gt;

&lt;pre class=&quot;lang:ps decode:true&quot;&gt;$ErrorActionPreference = &quot;Stop&quot;
Import-Module NombreDeModuloQueNoExiste
Write-Host &quot;Este código nunca llega a llamarse&quot;
&lt;/pre&gt;

&lt;p&gt;Personalmente soy partidario de poner el valor a &lt;strong&gt;Stop&lt;/strong&gt; al principio de los scripts, junto con el &lt;strong&gt;Set-StrictMode&lt;/strong&gt; y luego cambiar este valor puntualmente si así lo necesito en algún caso.&lt;/p&gt;
</description>
          <pubDate>2015-06-30T18:03:02+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/06/interrumpir-la-ejecucion-cuando-import-module-no-encuentra-el-modulo</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/06/interrumpir-la-ejecucion-cuando-import-module-no-encuentra-el-modulo</guid>
        </item>
      
    
      
        <item>
          <title>Polymorphic Equality</title>
          <description>&lt;p&gt;The default generation of Equality members provided by Resharper let you choose three different implementations when overriding the “Equals” method in a class (Alt+Insert -&amp;gt; Equality Members):&lt;/p&gt;

&lt;p&gt;The default choice is “Exactly the same type as ‘this’” which IS NOT polymorphic. I mean, subtypes of that class will be considered not equal regardless of the values:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/equalityGeneration.png&quot; alt=&quot;equalityGeneration&quot; /&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/a5a8f844c56c4c8b06a5e1a03e0d211d.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;On line 8 it compares the types which in the case of subtypes will be different thus returning false.&lt;/p&gt;

&lt;p&gt;I didn’t pay attention to this detail today and for some reason assumed that the comparison was going to work for subtypes. &lt;strong&gt;Lesson learned: always pay attention to generated code!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the generated code to consider subtypes equal:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/05af3d2c803559b4e76b0b86bc49c207.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;And this is yet another implementation that works:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/259d285d44183465f21815fff07e76dd.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The other lesson learned is that overriding the Equals method in the child class when the base class already overrides it, increases the complexity too much. The code is hard to follow and surprising. It increases the coupling between the child class and the parent.&lt;/p&gt;

&lt;p&gt;Avoid overriding the equality members in class hierarchies if you can.&lt;/p&gt;
</description>
          <pubDate>2015-06-23T22:06:33+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/06/polymorphic-equality</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/06/polymorphic-equality</guid>
        </item>
      
    
      
        <item>
          <title>¿Necesitas programar un servicio para Windows? Prueba Topshelf</title>
          <description>&lt;p&gt;Programar un servicio para Windows suele ser una tarea engorrosa y &lt;a href=&quot;http://topshelf-project.com/&quot;&gt;Topshelf&lt;/a&gt; proporciona una alternativa bastante interesante y muchísimo menos engorrosa que la plantilla por defecto que incorpora Visual Studio.&lt;/p&gt;

&lt;p&gt;Aunque podría enumerar bastantes aspectos interesantes de &lt;strong&gt;Topshelf&lt;/strong&gt;, me quedo con uno que para mi es fundamental, permite que una aplicación de consola sea un servicio de Windows. Esto significa que es posible recurrir a la aplicación de consola durante la fase de desarrollo o para su ejecución de forma independiente, pero que además es posible instalar esa aplicación de consola como un servicio Windows simplemente pasando un parámetro en su ejecución.&lt;/p&gt;

&lt;p&gt;Utilizar &lt;strong&gt;Topshelf&lt;/strong&gt; para crear un servicio de Windows es muy sencillo. Voy a describir los pasos básicos necesarios para dar un servicio, aunque luego podemos complicarlo bastante:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Creamos una aplicación de consola e instalamos el paquete &lt;strong&gt;Topshelf&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Añadimos una clase que contenga la lógica del servicio que queremos crear. El esqueleto podría ser como este: &lt;script src=&quot;https://gist.github.com/trikitrok/e2062248eec9fdb4f2897b7cf1a15796.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Modificamos la clase Main para configurar el servicio: &lt;script src=&quot;https://gist.github.com/trikitrok/99ef990b28c6225f81a16f091a0eea03.js&quot;&gt;&lt;/script&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En la &lt;a href=&quot;http://docs.topshelf-project.com/en/latest/&quot;&gt;documentación&lt;/a&gt; es posible encontrar muchos más detalles. Por ejemplo, además de poder configurar el código a ejecutar en el inicio (WhenStarted) o en la parada (WhenStopped), podemos configurar el comportamiento para la pausa (WhenPaused), continuación (WhenContinued) y el apagado (WhenShutdown).&lt;/p&gt;

&lt;p&gt;Una vez hecho esto tenemos una aplicación de consola que podemos ejecutar de forma individual, depurar desde Visual Studio o instalarla como servicio y &lt;strong&gt;Topshelf&lt;/strong&gt; se encargará de ejecutar el código correspondiente al inicio del servicio. Para instalar el servicio sólo es necesario ejecutar la aplicación de consola con el parámetro “install” y para desinstalarla con el parámetro “uninstall”.&lt;/p&gt;

&lt;p&gt;Muy importante a tener en cuenta es el usuario con el que se va a ejecutar el servicio. Por ejemplo, si en el servicio vamos a utilizar &lt;a href=&quot;http://owin.org/&quot;&gt;Owin&lt;/a&gt; para levantar una Web o un API, este código de ejemplo no funcionará porque si el servicio arranca como LocalSystem no tendrá los permisos adecuados.&lt;/p&gt;

&lt;p&gt;Es posible pasar otros parámetros para configurar el comportamiento deseado para el servicio en lo que a modo de inicio, usuario de ejecución, ejecución de comandos después de su instalación, etc. Lo mejor es ver la &lt;a href=&quot;http://docs.topshelf-project.com/en/latest/&quot;&gt;documentación&lt;/a&gt; para estar al tanto de todas las opciones.&lt;/p&gt;
</description>
          <pubDate>2015-06-15T23:44:42+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/06/necesitas-programar-un-servicio-para-windows-prueba-topshelf</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/06/necesitas-programar-un-servicio-para-windows-prueba-topshelf</guid>
        </item>
      
    
      
        <item>
          <title>Utilizando Exceptionless para monitorizar logs y excepciones</title>
          <description>&lt;p&gt;Cada vez que abordo un nuevo desarrollo, considero que la generación de trazas es una parte vital ya que es uno de los mecanismos que nos va a permitir diagnosticar e identificar cualquier tipo de problema cuando estemos en producción, en ocasiones incluso antes de que los propios usuarios lleguen a reportarlo.&lt;/p&gt;

&lt;p&gt;Hacer que nuestra aplicación genere las trazas adecuadas es una gran herramienta, no sólo para diagnosticar bugs, también permite identificar problemas relacionados con el rendimiento y otro tipo de funcionamientos anómalos de nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Durante los últimos años he utilizado &lt;a href=&quot;http://nlog-project.org/&quot;&gt;NLog&lt;/a&gt;, la librería de &lt;a href=&quot;http://www.theobjectguy.com/dotnetlog/&quot;&gt;The Object Guy&lt;/a&gt;, desarrollos propios y estos últimos meses he utilizado &lt;a href=&quot;http://serilog.net/&quot;&gt;Serilog&lt;/a&gt; en proyectos WPF, Web y WinRT. Pero siempre hay algo que no termina de convencerme, los interfaces para explorar los logs. He probado aplicaciones para Windows como &lt;a href=&quot;http://www.log-expert.de/&quot;&gt;LogExpert&lt;/a&gt;, &lt;a href=&quot;http://www.baremetalsoft.com/baretail/&quot;&gt;BareTail&lt;/a&gt;, &lt;a href=&quot;http://cbaxter.github.io/Harvester/&quot;&gt;Harvester&lt;/a&gt;, &lt;a href=&quot;http://tailforwin32.sourceforge.net/&quot;&gt;Tail for Win32&lt;/a&gt;, o soluciones más trabajadas como &lt;a href=&quot;http://www.splunk.com/&quot;&gt;Splunk&lt;/a&gt; o &lt;a href=&quot;https://logentries.com/&quot;&gt;LogEntries&lt;/a&gt;, pero al final ninguna me ha convencido por funcionalidad o por coste.&lt;/p&gt;

&lt;p&gt;Hace unos meses me encontré con &lt;a href=&quot;https://exceptionless.com/&quot;&gt;ExceptionLess&lt;/a&gt; y me pareció un proyecto bastante interesante. A modo de resumen, estos son algunos de los puntos que me parecieron interesantes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Puedo utilizarlos como servicio o montarlo sobre mi propia infraestructura.&lt;/li&gt;
  &lt;li&gt;Dispone de librerías PCL con soporte offline. Lo que significa que puedo utilizarlo en la tablet y, cuando no tenga conexión, guarda los logs en local para enviarlos cuando la conexión vuelva.&lt;/li&gt;
  &lt;li&gt;Tiene soporte de notificaciones.&lt;/li&gt;
  &lt;li&gt;Puedo adjuntar objetos complejos a las trazas, para poder consultarlos cuando vea la traza desde la UI. Básicamente, si se puede serializar en Json, se puede adjuntar.&lt;/li&gt;
  &lt;li&gt;Me intenta facilitar la identificación de problemas/patrones agrupando las trazas o mostrando las que más se producen.&lt;/li&gt;
  &lt;li&gt;Es Open Source. Y esto me parece especialmente importante porque me permite solucionar algunas de las carencias menores que estoy encontrando (ya sólo me falta aprender Angular ;P).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y como no todo son cosas buenas, me parece importante remarcar algunas cosas que no me han gustado durante su uso:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;El interfaz de usuario aún está un poco verde. Tiene algunos detalles de interfaz que desorientan un poco. Cosas tontas como que al darle a buscar no te mande al listado con los resultados de la búsqueda si estás en el detalle de un log. Simplemente establece el filtro como el filtro activo, pero tienes tú que irte al listado de logs para poder verlos.&lt;/li&gt;
  &lt;li&gt;Está muy orientado a que lo uses con su plataforma. Esto se nota muchísimo al configurarlo en un servidor propio en detalles como que las configuraciones por defecto apunten a su dominio (exceptionless.io) o que aspectos de la configuración de servidor y de los clientes son distintos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ojo-si-quieres-configurar-exceptionless-en-tu-propio-servidor&quot;&gt;Ojo si quieres configurar ExceptionLess en tu propio servidor&lt;/h2&gt;

&lt;p&gt;No tiene sentido hacer un tutorial sobre cómo configurarlo en local porque en github están las instrucciones y no son complicadas. Únicamente es necesario tener MongoDB y ElasticSearch. En caso de montar varios servidores de API, es necesario Redis, pero para un único nodo no es necesario y utiliza una implementación en memoria.&lt;/p&gt;

&lt;p&gt;Ten en cuenta que necesitas instalar dos proyectos, el &lt;a href=&quot;https://github.com/exceptionless/Exceptionless&quot;&gt;API&lt;/a&gt; y la &lt;a href=&quot;https://github.com/exceptionless/Exceptionless.UI&quot;&gt;UI&lt;/a&gt;. Para este ejemplo, supongamos una configuración local de pruebas con el API instalado en: http://localhost/ExceptionLess.API&lt;/p&gt;

&lt;p&gt;Al instalar la UI, es necesario editar el fichero &lt;strong&gt;&lt;em&gt;app.config&lt;/em&gt;&lt;/strong&gt; para especificar en la clave &lt;strong&gt;BASE_URL&lt;/strong&gt; la url del API. Pues bien, aunque la primera opción parece que sería poner la url ‘http://localhost/ExceptionLess.API’, al hacer esto no va a funcionar. La url correcta que hay que configurar es: &lt;strong&gt;‘http://localhost/ExceptionLess.API/api/v2’&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sin embargo, para enviar logs a ese servidor desde una &lt;strong&gt;aplicación .Net&lt;/strong&gt;, la url que debo configurar si que es &lt;strong&gt;‘http://localhost/ExceptionLess.API’&lt;/strong&gt;. Esto me volvió un poco loco al principio.&lt;/p&gt;

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

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

</description>
          <pubDate>2015-06-05T18:11:52+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/06/utilizando-exceptionless-para-monitorizar-logs-y-excepciones</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/06/utilizando-exceptionless-para-monitorizar-logs-y-excepciones</guid>
        </item>
      
    
      
        <item>
          <title>C# Async/Await and Task Parallel Library</title>
          <description>&lt;p&gt;In order for a native desktop application to be responsive, I mean, not to freeze while sending a request over the network or processing a heavy CPU operation, these operations have to run in a separate thread.&lt;/p&gt;

&lt;p&gt;.Net 4.0 introduced &lt;strong&gt;promises&lt;/strong&gt; (a well-known concept for JavaScript developers), the &lt;strong&gt;Task object is a promise&lt;/strong&gt; in C#. Later on, C# 5.0 introduced a nice syntactic helper to work with theses promises: &lt;strong&gt;async and await&lt;/strong&gt; keywords.&lt;/p&gt;

&lt;p&gt;Powerful features, comfortable to develop with but it’s important to know how they work behind scenes. Otherwise you could get in trouble with &lt;strong&gt;deadlocks&lt;/strong&gt; and invalid operation &lt;strong&gt;exceptions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our teammate &lt;a href=&quot;http://www.modestosanjuan.com/&quot;&gt;Modesto San Juan&lt;/a&gt; recommended the book &lt;a href=&quot;http://shop.oreilly.com/product/0636920026532.do&quot;&gt;“Async in C# 5.0”&lt;/a&gt;  by &lt;a href=&quot;https://twitter.com/alexcode&quot;&gt;Alex Davies&lt;/a&gt;, and I found it great. I’ve created a tiny sample app to summarize the things I’ve learned from the book:&lt;/p&gt;

&lt;p&gt;Sample app: &lt;a href=&quot;https://bitbucket.org/carlosble/asyncawait&quot;&gt;https://bitbucket.org/carlosble/asyncawait&lt;/a&gt; - Look at &lt;strong&gt;MainWindow.xaml.cs&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;The app is just a window with a bunch of buttons and a text field. Every button has an event handler in the MainWindow.xaml.cs that exercises each use case.&lt;/p&gt;

&lt;p&gt;The method names in that file along with some comments, explain the most remarkable features for our team right now.&lt;/p&gt;

&lt;p&gt;Most of the stuff in Alex’s book is very well summarized in this presentation by &lt;a href=&quot;https://twitter.com/acasquete&quot;&gt;Alex Casquete&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://twitter.com/lluisFranco&quot;&gt;Lluis Franco&lt;/a&gt;:&lt;/p&gt;

&lt;div style=&quot;margin-bottom:5px&quot;&gt;
  &lt;strong&gt; &lt;a href=&quot;//www.slideshare.net/lluisfranco/async-best-practices&quot; title=&quot;Async Best Practices&quot;&gt;Async Best Practices&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;//www.slideshare.net/lluisfranco&quot;&gt;Fimarge&lt;/a&gt;&lt;/strong&gt;
&lt;/div&gt;
</description>
          <pubDate>2015-05-29T14:04:27+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/05/c-asynawait-and-task-parallel-library</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/05/c-asynawait-and-task-parallel-library</guid>
        </item>
      
    
      
        <item>
          <title>Cómo crear Appx para Sideloading desde Integración Continua</title>
          <description>&lt;p&gt;Cuando trabajamos con aplicaciones para la tienda de Windows, hay escenarios en los que necesitamos hacer Sideloading. Básicamente el Sideloading nos permite instalar una aplicación de la tienda de Windows, sin utilizar la tienda de Windows. Las razones para querer hacer Sideloading pueden ser muchas: probar la aplicación en local antes de subirla a la tienda, instalar la aplicación en algunos dispositivos para hacer testing en friends&amp;amp;family o simplemente utilizar la aplicación a nivel corporativo fuera de la tienda de Windows.&lt;/p&gt;

&lt;p&gt;En uno de los proyectos en los que estoy trabajando ahora mismo nos encontramos dentro de esos escenarios. Tenemos una aplicación que se distribuye mediante Sideloading y además tenemos un equipo de Q&amp;amp;A que prueba tanto las versiones de desarrollo como las release candidate.&lt;/p&gt;

&lt;p&gt;Como resultaba bastante pesado tener que estar dependiendo de generar los paquetes para Sideloading de forma manual, decidimos crear estos paquetes de forma manual desde nuestro entorno de integración continua. En este caso utilizamos Jenkins, pero lo aquí descrito funciona para cualquier otro sistema.&lt;/p&gt;

&lt;p&gt;Microsoftnos dice en &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh924768.aspx&quot;&gt;este&lt;/a&gt; enlace cómo crear un paquete utilizando msbuild. Básicamente se limita a pedir a msbuild que compile el proyecto de la app para la tienda de Windows:&lt;/p&gt;

&lt;pre class=&quot;lang:default decode:true&quot;&gt;MSBuild MyProject.csproj /p:OutDir=C:\builds\droplocation\&lt;/pre&gt;

&lt;p&gt;El problema de esta aproximación es que en proyectos grandes, es normal tener una solución con varios proyectos (pero sin pasarse eh!). Al tener varios proyectos solemos tener una estructura de carpetas que implica que, al compilar un proyecto de forma independiente, msbuild nos de problemas para encontrar los paquetes de nuget porque los busca de forma relativa a la ruta de la solución y no a la ruta del proyecto.&lt;/p&gt;

&lt;p&gt;En fin, tengamos este problema o no, que podría solucionarse de muchas otras formas, una manera muy sencilla de tener un paquete de aplicación es modificar el .csproj para que cree el paquete de aplicación cada vez que compilamos el proyecto (sea dentro de una solución o de forma independiente). Para ello tenemos que añadir estas líneas al .csproj de nuestra aplicación de la tienda:&lt;/p&gt;

&lt;pre class=&quot;lang:xhtml decode:true&quot;&gt;&amp;lt;PropertyGroup Condition=&quot;&apos;$(BuildingInsideVisualStudio)&apos; != &apos;true&apos;&quot;&amp;gt;
  &amp;lt;GenerateAppxPackageOnBuild&amp;gt;True&amp;lt;/GenerateAppxPackageOnBuild&amp;gt;
  &amp;lt;AppxPackageDir&amp;gt;$(OutputPath)AppPackages&amp;lt;/AppxPackageDir&amp;gt;
  &amp;lt;AppxPackageName&amp;gt;$(AssemblyName)_$(Platform)&amp;lt;/AppxPackageName&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;    
&lt;/pre&gt;

&lt;p&gt;Es muy importante tener en cuenta el atributo &lt;strong&gt;Condition&lt;/strong&gt; del PropertyGroup, ya que así evitamos que se genere el paquete de la aplicación cada vez que la compilamos desde Visual Studio (no queremos penalizar el tiempo de compilación del equipo de desarrollo). Por supuesto, podemos cambiar esta condición por una que tenga en cuenta el perfil de compilación o cualquier otro factor, pero a nosotros nos ha parecido bastante adecuada esta.&lt;/p&gt;

&lt;p&gt;Por otro lado, al especificar el &lt;strong&gt;AppxPackageName&lt;/strong&gt; conseguimos tener siempre un el mismo nombre de archivo .appx, para evitar que el criterio por defecto de que el número de versión se incluya en el nombre del archivo. Así facilitamos la vida de cara a los procesos de automatización que describiré en próximas entradas.&lt;/p&gt;

&lt;p&gt;Otro detalle importante a tener en cuenta es especificar en el nombre del paquete la plataforma, porque en alguna ocasión me ha pasado que msbuild genera los .appx de 32 y 64 bits dentro de la misma carpeta, machacando el primero al generar el último, lo que dará grandes quebraderos de cabeza.&lt;/p&gt;

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

</description>
          <pubDate>2015-05-13T06:45:57+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/05/como-crear-appx-para-sideloading-desde-integracion-continua</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/05/como-crear-appx-para-sideloading-desde-integracion-continua</guid>
        </item>
      
    
      
        <item>
          <title>Mocking (stubbing) async calls (async/await)</title>
          <description>&lt;p&gt;.Net 4.5 came out with a really handy built-in asynchronous mechanism, &lt;em&gt;async and await&lt;/em&gt;. However the method signature of a void method is a bit strange:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/84a02a4e739d15edbff016d08294b033.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;It is possible to use &lt;em&gt;async void&lt;/em&gt; but it’s &lt;a title=&quot;Best Practices in Asynchronous Programming&quot; href=&quot;https://msdn.microsoft.com/en-us/magazine/jj991977.aspx&quot;&gt;not recommended&lt;/a&gt; unless we are talking about event handlers. It’s also a bit strange the fact that the type specified in the signature is not the one returned:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/79a25b08d1d01ca5b00cbe2f6e0a2a52.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;But everything else is great and very handy.&lt;/p&gt;

&lt;p&gt;Stubbing method calls can be hard though. You can get weird exceptions like System.AggregateException when running tests with NUnit. The problem comes up when awaiting for a&lt;/p&gt;

&lt;p&gt;stubbed async method:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/d174eaea90231e3cc759df0d481214e3.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The problem is that &lt;a href=&quot;https://github.com/moq/moq&quot;&gt;Moq&lt;/a&gt; will make the stubbed method return &lt;strong&gt;null&lt;/strong&gt; when invoked, because we are not specifying any return value. The default value for Task&lt;string&gt; is null. We should tell Moq to return a proper Task:&lt;/string&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/trikitrok/5da29ff06c346cdaf63b56f1794acef8.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;The key is to return a new task: &lt;em&gt;Task.Factory.StartNew(lambda)&lt;/em&gt;&lt;/p&gt;
</description>
          <pubDate>2015-02-10T11:57:16+00:00</pubDate>
          <link>https://www.codesai.com/posts/2015/02/mocking-stubbing-async-calls-asyncawait</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2015/02/mocking-stubbing-async-calls-asyncawait</guid>
        </item>
      
    
      
        <item>
          <title>Practising Mob Programming</title>
          <description>&lt;p&gt;&lt;img src=&quot;/assets/mobProg1.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the past edition of Socrates UK, I met &lt;a title=&quot;Gianfranco Alongi&quot; href=&quot;https://twitter.com/gfalongi&quot;&gt;Gianfranco Alongi&lt;/a&gt; who told us about his team’s experience with &lt;a title=&quot;Mob Programming site&quot; href=&quot;http://mobprogramming.org/&quot;&gt;Mob Programming&lt;/a&gt;. It was the first time I heard about it. As the site says, Mob programming is &lt;em&gt;people working at the same time, in the same space, at the same computer, on the same thing.&lt;/em&gt; Gianfranco said it was very useful for them.&lt;/p&gt;

&lt;p&gt;At the beginning of November three of my fellow craftsmen and I joined a team of other 12 developers to work on a new project. We are building a &lt;a title=&quot;DMS&quot; href=&quot;http://en.wikipedia.org/wiki/Dealership_management_system&quot;&gt;DMS&lt;/a&gt; (Dealer management system) and an IMS (Importer management system). The project is very exciting but we don’t have a clue on the domain. We are also a lot of people with different programming styles. So we decided to give Mob Programming a try and after a few weeks the results are very positive.&lt;/p&gt;

&lt;p&gt;Some &lt;strong&gt;lessons we have learned&lt;/strong&gt; along the way:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Like with pair programming, &lt;strong&gt;navigators should take notes&lt;/strong&gt; whilst the driver is at the keyboard, rather than disturbing him constantly.&lt;/li&gt;
  &lt;li&gt;Only when the driver raises his &lt;strong&gt;hands off the keyboard we are allowed to discuss&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rotate&lt;/strong&gt; frequently: it’s faster to jump in the keyboard and do it yourself than trying to explain the code you envision.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Limit the group size&lt;/strong&gt; to 5 or 6 people. We find that 4 is a good number, more than that is not being productive for us. Sometimes it’s useful though, when we want to define conventions for the whole team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The group should be stable&lt;/strong&gt;: if new people join the discussion in the middle then we have to explain again and again the code and the decisions we have already made. It’s like the never ending story.&lt;/li&gt;
  &lt;li&gt;At some point I had to leave a session right in the middle of something. When I came back a colleague told me that the people who were shy or less proactive during my driving period, started proposing interesting ideas during my absence. The people considered &lt;strong&gt;“seasoned” or “experienced” should go away from time to time&lt;/strong&gt; for the others to feel empowered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far the project is just fantastic. &lt;strong&gt;People are awesome&lt;/strong&gt;, learning incredibly fast, very enthusiastic. Everyone wants to learn and contribute. We are all learning a lot and doing our best. I can’t think of a better project. We are very lucky.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/mobProg2.jpg&quot; alt=&quot;mobProg2&quot; /&gt;&lt;/p&gt;

</description>
          <pubDate>2014-12-02T01:50:48+00:00</pubDate>
          <link>https://www.codesai.com/posts/2014/12/practising-mob-programming</link>
          <guid isPermaLink="true">https://www.codesai.com/posts/2014/12/practising-mob-programming</guid>
        </item>
      
    
  </channel>
</rss>