<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Mateus Costa</title>
    <description></description>
    <link>https://mrcosta.github.io/</link>
    <atom:link href="https://mrcosta.github.io/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Thu, 23 Jul 2026 14:21:17 +0000</pubDate>
    <lastBuildDate>Thu, 23 Jul 2026 14:21:17 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Fragments (pieces of I read) - 07.2026</title>
        <description>&lt;p&gt;(Inspired by &lt;a href=&quot;https://martinfowler.com/articles/writing-fragments.html&quot;&gt;Martin Fowler&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Some pieces from &lt;a href=&quot;https://dominikgronkiewicz.com/blog/the-developer-divide/&quot;&gt;The Developer Divide — What the Pragmatic Engineer’s 900-Developer Survey Actually Reveals About AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Pragmatic Engineer survey identified three developer archetypes in the age of Al: Builders, Shippers and Coasters. The central insight is not that one group is right and the others are wrong. It is that Al amplifies existing tendencies. It does not make everyone faster. It makes who you already are more intense.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Builders&lt;/strong&gt; care about quality, architecture and craft. They do the large refactors, the migrations, the test coverage work.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Shippers&lt;/strong&gt; care about output. They ship features fast and measure success by what reaches production.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Coasters&lt;/strong&gt; are engineers who were average before Al and are now, with the right tools, producing more code than ever, but with proportionally more problems.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The critical finding: each group experiences Al completely differently. What feels like speed to a shipper feels like noise to a builder. What feels like a promotion to a coaster feels like a tax to everyone else.&lt;/p&gt;
</description>
        <pubDate>Mon, 13 Jul 2026 22:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2026-07-13-fragments-07-2026</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2026-07-13-fragments-07-2026</guid>
        
        
        <category>read, interesting, ai, work</category>
        
      </item>
    
      <item>
        <title>Fragments (pieces of I read) - 04.2026</title>
        <description>&lt;p&gt;(Inspired by &lt;a href=&quot;https://martinfowler.com/articles/writing-fragments.html&quot;&gt;Martin Fowler&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Some pieces from &lt;a href=&quot;https://www.thoughtworks.com/en-de/radar&quot;&gt;Tech Radar&lt;/a&gt;(Volume 34 - April 2026)&lt;/p&gt;

&lt;h1 id=&quot;measuring-collaboration-quality-with-coding-agents&quot;&gt;Measuring collaboration quality with coding agents&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;Metrics such as first-pass acceptance rate, iteration cycles per task, post-merge rework, failed builds and review burden provide more meaningful signals than speed alone. 
Teams using Claude Code can use the /insights command to generate reports reflecting on successes and challenges from agent sessions. Our teams have also experimented with tracking first-pass acceptance of a customized /review command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;agent-instruction-bloat&quot;&gt;Agent instruction bloat&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;Context files such as AGENTS.md and CLAUDE.md tend to accumulate over time as teams add codebase overviews, architectural explanations, conventions and rules. 
While each addition is useful in isolation, this often leads to agent instruction bloat. Instructions become long and sometimes conflict with each other. Models tend to attend less to content buried in the middle of long contexts, so guidance deep in a long conversation history can be missed. As instructions grow, the likelihood increases that important rules are ignored.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;ai-accelerated-shadow-it&quot;&gt;AI-accelerated shadow IT&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;AI continues to lower the barriers for noncoders to build complex systems. While this enables experimentation and early validation of requirements, it also introduces the risk of AI-accelerated shadow IT. In addition to no-code workflow platforms integrating AI APIs (e.g., OpenAI or Anthropic), more agentic tools are becoming available to noncoders, such as Claude Cowork.
When the spreadsheet that quietly runs the business evolves into customized agentic workflows that lack governance, it introduces significant security risks and a proliferation of competing solutions to similar problems. Distinguishing between disposable, one-off workflows and critical processes that require durable, production-ready implementation is key to balancing experimentation with control.
Organizations should prioritize governance as part of their AI adoption strategy by facilitating experimentation within controlled environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;codebase-cognitive-debt&quot;&gt;Codebase cognitive debt&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;Codebase cognitive debt is the growing gap between a system’s implementation and a team’s shared understanding of how and why it works. As AI increases change velocity, especially with multiple contributors or Coding Agent Swarms, teams can lose track of design intent and hidden coupling. This, combined with rising technical debt, creates a reinforcing loop that makes systems progressively harder to reason about.
Weaker system understanding also reduces developers’ ability to guide AI effectively, making it harder to anticipate edge cases and steer agents away from architectural pitfalls. Left unmanaged, teams reach a tipping point where small changes trigger unexpected failures, fixes introduce regressions and cleanup efforts increase risk instead of reducing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;feedback-sensors-for-coding-agents&quot;&gt;Feedback sensors for coding agents&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;To make coding agents more effective and reduce the load on human reviewers, teams need feedback loops that agents can directly access. These feedback sensors for coding agents act as a form of feedback backpressure, increasing trust in generated results. Developers have long relied on deterministic quality gates such as compilers, linters, structural tests and test suites; here, they’re wired into agentic workflows so that failures trigger timely self-correction.
These checks reduce routine steering work for the human in the loop. Teams can implement them in different ways, such as introducing a reviewer agent responsible for running checks and triggering corrections, or by exposing the checks through a companion process that runs in parallel that agents can query efficiently. Coding agents also make it cheaper to build custom linters and structural tests, further strengthening these feedback loops. Whenever possible, these sensors should run during the coding session and report clean results before a commit is made, rather than relying on post-commit checks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;complacency-with-ai-generated-code&quot;&gt;Complacency with AI-generated code&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;As AI coding assistants and agents gain traction, so does the body of data and research highlighting concerns about complacency with AI-generated code. While there’s ample evidence these tools can accelerate development — especially for prototyping and greenfield projects — studies show that code quality can decline over time.
GitClear’s 2024 research found that duplicate code and code churn have risen more than expected, while refactoring activity in commit histories has dropped. Reflecting a similar trend, Microsoft research on knowledge workers shows that AI-driven confidence often comes at the expense of critical thinking — a pattern we’ve observed as complacency sets in with prolonged use of coding assistants.
The rise of coding agents further amplifies these risks, since AI now generates larger change sets that are harder to review. As with any system, speeding up one part of the workflow increases pressure on the others. Our teams are finding that using AI effectively in production requires renewed focus on code quality. We recommend reinforcing established practices such as TDD and static analysis, and embedding them directly into coding workflows, for example through curated shared instructions for software teams.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Fri, 17 Apr 2026 22:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2026-04-17-fragments-04-2026</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2026-04-17-fragments-04-2026</guid>
        
        
        <category>read, interesting, ai, work</category>
        
      </item>
    
      <item>
        <title>Fragments (pieces of I read) - 03.2026</title>
        <description>&lt;p&gt;(Inspired by &lt;a href=&quot;https://martinfowler.com/articles/writing-fragments.html&quot;&gt;Martin Fowler&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Some pieces from &lt;a href=&quot;https://stopsloppypasta.ai/en/&quot;&gt;Stop Sloppypasta&lt;/a&gt; I thought were interesting:&lt;/p&gt;

&lt;p&gt;Too long, didn’t read:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;slop·py·pas·ta&lt;/strong&gt;  n.  Verbatim LLM output copy-pasted at someone, unread, unrefined, and unrequested. From slop (low-quality AI-generated content) + copypasta (text copied and pasted, often as a meme, without critical thought). It is considered rude because it asks the recipient to do work the sender did not bother to do themselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;the-eager-beaver&quot;&gt;The Eager Beaver&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;A conversation participant wants to contribute to the topic at hand, so they ask a chatbot and share whatever comes back. The intention is good - they genuinely want to help - but the wall of generic AI text they contributed blocks the discussion already underway. Now other participants have to scroll past it to continue, or stop to read and validate it.
It feels helpful to send. It creates work to receive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;the-oraicle&quot;&gt;The OrAIcle&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;Someone asks a specific question. Another person puts it into a chatbot and pastes the response as the answer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;the-ghostwriter&quot;&gt;The Ghostwriter&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;The sender shares AI output as their own work, with no indication a chatbot wrote it. Recipients have no reason to question it, and may act on information that is out of date, incomplete, or simply wrong.
Using AI as a ghostwriter borrows the sender’s credibility. If the content turns out to be wrong, that credibility is what gets spent.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Mon, 09 Mar 2026 22:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2026-03-09-fragments-03-2026</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2026-03-09-fragments-03-2026</guid>
        
        
        <category>read, interesting, ai, work</category>
        
      </item>
    
      <item>
        <title>Fragments (pieces of I read) - 02.2026</title>
        <description>&lt;p&gt;(Inspired by &lt;a href=&quot;https://martinfowler.com/articles/writing-fragments.html&quot;&gt;Martin Fowler&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Some pieces from &lt;a href=&quot;https://openai.com/index/harness-engineering/&quot;&gt;Harness engineering: leveraging Codex in an agent-first world&lt;/a&gt; I thought were interesting:&lt;/p&gt;

&lt;h1 id=&quot;about-agentsmd&quot;&gt;About AGENTS.md&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;We tried the “one big AGENTS.md” approach. It failed in predictable ways:
Context is a scarce resource. A giant instruction file crowds out the task, the code, and the relevant docs—so the agent either misses key constraints or starts optimizing for the wrong ones.
Too much guidance becomes non-guidance. When everything is “important,” nothing is. Agents end up pattern-matching locally instead of navigating intentionally.
It rots instantly. A monolithic manual turns into a graveyard of stale rules. Agents can’t tell what’s still true, humans stop maintaining it, and the file quietly becomes an attractive nuisance.
It’s hard to verify. A single blob doesn’t lend itself to mechanical checks (coverage, freshness, ownership, cross-links), so drift is inevitable.
So instead of treating AGENTS.md as the encyclopedia, we treat it as the table of contents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;about-asynchronous-decisions-in-different-channels&quot;&gt;About asynchronous decisions in different channels&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;We learned that we needed to push more and more context into the repo over time. That Slack discussion that aligned the team on an architectural pattern? If it isn’t discoverable to the agent, it’s illegible in the same way it would be unknown to a new hire joining three months later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;about-ai-guardrails&quot;&gt;About AI Guardrails&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;In practice, we enforce these rules with custom linters and structural tests, plus a small set of “taste invariants.” For example, we statically enforce structured logging, naming conventions for schemas and types, file size limits, and platform-specific reliability requirements with custom lints. Because the lints are custom, we write the error messages to inject remediation instructions into agent context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;In a human-first workflow, these rules might feel pedantic or constraining. With agents, they become multipliers: once encoded, they apply everywhere at once.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Human taste is fed back into the system continuously. Review comments, refactoring pull requests, and user-facing bugs are captured as documentation updates or encoded directly into tooling. When documentation falls short, we promote the rule into code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The resulting code does not always match human stylistic preferences, and that’s okay. As long as the output is correct, maintainable, and legible to future agent runs, it meets the bar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;about-feedback-loops-and-merge-gates&quot;&gt;About feedback loops and merge gates&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;The repository operates with minimal blocking merge gates. Pull requests are short-lived. Test flakes are often addressed with follow-up runs rather than blocking progress indefinitely. In a system where agent throughput far exceeds human attention, corrections are cheap, and waiting is expensive.
This would be irresponsible in a low-throughput environment. Here, it’s often the right tradeoff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;about-humans-in-the-loop&quot;&gt;About humans in the loop&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;Humans always remain in the loop, but work at a different layer of abstraction than we used to. We prioritize work, translate user feedback into acceptance criteria, and validate outcomes. When the agent struggles, we treat it as a signal: identify what is missing—tools, guardrails, documentation—and feed it back into the repository, always by having Codex itself write the fix.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
        <pubDate>Wed, 25 Feb 2026 22:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2026-02-25-fragments-02-2026</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2026-02-25-fragments-02-2026</guid>
        
        
        <category>read, interesting, ai, work</category>
        
      </item>
    
      <item>
        <title>From @Test to #[test]: an essay about testing between Java and Rust</title>
        <description>
&lt;p&gt;A disclaimer about used terms in the text: I’ve seen along the years that some definitions about testing have different meanings to developers. So everything here it’s based on my experience along the years: the projects that I was involved, the people that I worked with, blog posts and books that I read, etc.&lt;/p&gt;

&lt;h1 id=&quot;unit-testing-in-the-projects-that-ive-worked&quot;&gt;Unit Testing in the projects that I’ve worked&lt;/h1&gt;

&lt;p&gt;It was working with Groovy that I have my first contact with &lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;Test Driven Development&lt;/a&gt;, and looking back today, I can say that people in my team was not pragmatic regarding the &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;Test Pyramid&lt;/a&gt;. We aimed for a high percentage for test coverage in all the pyramid levels. I remember that our concept of &lt;a href=&quot;https://martinfowler.com/bliki/IntegrationTest.html&quot;&gt;integration tests&lt;/a&gt; was a very specific one.&lt;/p&gt;

&lt;p&gt;Basically two objects (two Groovy classes) interacting to each other was considered an integration and, since we were using a more &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;mockist approach&lt;/a&gt; we used a lot of stubs and mocks. At this point, you can imagine that we had a lot of redundant tests since is impossible to multiples objects to work without some kind of interaction/dependency between them. I think this project was extreme, but since then I carried this mindset with me always trying to test almost everything.&lt;/p&gt;

&lt;p&gt;I was working with Java in my previous company as a consultant and it was a company that was pretty much by the book regarding practices like TDD and other buzzwords in our area as selling points to clients. I remembering convincing one developer to do a very complex unit test that was hard to set up to assert that a log statement was printed. This log statement was being used for our monitoring. And even that my arguments at the time were good, I think we could achieve better things to the business instead of spending almost 3 days to set up something complex to test a cross-functional requirement that could be easily manually tested in a few minutes.&lt;/p&gt;

&lt;p&gt;Another case was to test some complex environment configuration to make sure it was there during the startup of the application. Again, my conclusion today is that the time spent trying to test something complex that could be just confirmed starting the application and would give the same confidence than with a complex test would be better to the business.&lt;/p&gt;

&lt;p&gt;Of course, in both cases, we would miss a lot of benefits on the long term like regression and documentation, but even considering this I think it would not be worth doing with a test that required so long time to setup.&lt;/p&gt;

&lt;p&gt;Most of the projects that I worked with Java had this similar mindset that I have described. My mindset had changed in my last project where I worked with a very experienced developer that was more pragmatic with some specific tests and was always reminding me about &lt;strong&gt;how important it is to solve the clients’ problems with quality but being pragmatic when testing some complex things or just forget for a moment about writing several unit tests and invest in at least a few integration tests&lt;/strong&gt;. These things I didn’t learn in any book. You need to understand your context and have experience with different scenarios, projects, problems, deadlines and people. These details on everyday routine are going to give you enough knowledge to find a good decision that works with the scenario at hand.&lt;/p&gt;

&lt;h1 id=&quot;some-differences-between-testing-in-rust-and-java&quot;&gt;Some differences between Testing in Rust and Java&lt;/h1&gt;

&lt;p&gt;These stories were told to give an idea of how much I struggled with testing in Rust when I started.&lt;/p&gt;

&lt;p&gt;In Java, we need at least one dependency (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JUnit&lt;/code&gt;) to write unit tests and Rust has support for unit tests in the language by default. I think this is amazing since the possibility of doing tests is just &lt;strong&gt;there&lt;/strong&gt; and the syntax is pretty much the same as writing production code. Of course, as your project grows, things get more complex and then you may need some external help from other crates.&lt;/p&gt;

&lt;p&gt;Another big difference for me is where you write your unit tests. In Java, you usually have a file for your production code and another one for testing. In Rust, you write them together in the same file.&lt;/p&gt;

&lt;p&gt;This was weird for me in the beginning, but it was the beginning! Nothing weird to feel weird if it’s something that you’re starting to do. Today it makes complete sense since is easier to look at the code and understand what is wrong if some test is falling or some scenario is missing. And of course, they are not compiled in the final binary since rust exclude everything with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[test]&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Another thing is the number of scenarios that you need to write. It changes since you don’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; like java. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; in Java can leave you to think in edge cases later, since you can easily get to a situation like &lt;em&gt;“I don’t want to think in error handling now, let’s just return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;“&lt;/em&gt;. And then when running the production code you realize that there is this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; case that needs to be treated. Rust forces you to think better in the edge cases where things can go wrong since you probably are going to work with types like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Option&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Result&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;a-practical-example&quot;&gt;A practical example&lt;/h1&gt;

&lt;p&gt;I was implementing a new endpoint in our Rust project at &lt;a href=&quot;https://impero.com/&quot;&gt;Impero&lt;/a&gt; with a function that looked pretty much like this:&lt;/p&gt;

&lt;div class=&quot;language-rust 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;#[get(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/process_query&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;process_query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query_executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;QueryExecutor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InternalError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;something&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_executor&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.call_to_database_that_return_something&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;complex_private_method_logic_that_I_wanted_to_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;something&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In Java I would choose between two testing approaches:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;an integration test that would hit the endpoint and use an in-memory database&lt;/li&gt;
  &lt;li&gt;a unit test calling the public method and use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mock&lt;/code&gt; returning something realistic from the database that I could work with afterwards.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some people probably are going to have a strong opinion here about the way to test but I like what &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck&lt;/a&gt; says in this &lt;a href=&quot;https://pythontesting.net/transcripts/transcript-epsiode-23-lessons-testing-tdd-kent-beck/&quot;&gt;podcast&lt;/a&gt; about TDD and testing or what kind of specific test you should write in a specific situation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think the level, the interface where you apply your tests, is a pragmatic decision based on the circumstances you’re in. I write tests at whatever scale I need them to be to help me make my next step of progress. Part of the skill of TDD is learning to move between scales, right. So I write a test that my customer says, “this scenario should result in a five”. So you write a test that says this scenario should result in a five, and then you’re down deep in the intestines of your program and you’re thinking, oh, I see, well this object when given a five and a seven should return the five. Well, that’s a good place to write a test because that’s another piece of the story that needs to be told. But, you know, is that Acceptance Test Driven Development, or is that BDD? I think that erecting rigid walls between the styles is actually a mistake, like the scales, as a programmer I want to understand all those scales. Tests help me understand, so I write tests at all those scales.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I tried to apply the number two (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mock&lt;/code&gt;) with Rust but there is a problem. There aren’t still good mocking crates (you can check a good comparison table &lt;a href=&quot;https://asomers.github.io/mock_shootout&quot;&gt;here&lt;/a&gt;) for structures. It’s being some time since I’ve faced this issue, but I remember the problem was related to being hard to create mocks for structs in external crates (and the struct to access the database was complex). I remember reading these two posts &lt;a href=&quot;https://klau.si/blog/mocking-in-rust-with-conditional-compilation/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://tech.labs.oliverwyman.com/blog/2018/05/21/on-mocking-rust/&quot;&gt;here&lt;/a&gt;, and this good discussion &lt;a href=&quot;https://www.reddit.com/r/rust/comments/d2puv7/how_to_mock_calls_to_databases/&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Rust does not have a concept of object inheritance for structs so there is no way to mimic a struct type from the standard library or an external crate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope as I get more fluency with the language and with new or more mature crates I can manage to do this without problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another way to see the problem&lt;/strong&gt;: maybe my design was broken. And yes this, in fact, can be one of the answers when I compare the way that a connection is passed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt; or how the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_inversion_principle&quot;&gt;Dependency Inversion Principle&lt;/a&gt; works, but this right now seems a question for the future. I’m still exploring the language in other aspects and even that I could say how this is made in other languages, I think I need to see more to have an elaborated opinion.&lt;/p&gt;

&lt;p&gt;But back to the testing strategy: &lt;strong&gt;How did I test the code?&lt;/strong&gt;. In fact, pairing with my colleague he comes up with a very simple solution:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;it’s just one line of code that is making this database call and it’s been already isolated tested in another place, so let’s just test the isolated private function and move on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s what we did, and it was hard for me to let it go at the time, but today I understand that was a good decision.&lt;/p&gt;

&lt;p&gt;In Java, people would complete forbid this and start screaming about how we only test the public API’s/public methods. And I understand it, since is also the way that the language was designed and consequently how the libraries supporting the ecosystem also is going to be affected by that.&lt;/p&gt;

&lt;p&gt;I only wanted to highlight that the testing approach here can be different because the two languages are different. Not just by design, but also in how each community can approach practices that are not linked by the language itself.&lt;/p&gt;

&lt;p&gt;Another example: I see the &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;Single Responsibility Principle&lt;/a&gt; with a different way in Rust than Java. In my experience, in Java, is more common for developers to create smaller classes with small methods while in Rust I see that is more forgivable to have more modules with way more lines that I have seen in Java classes. And this, in general, it’s ok I think. The community of either language will figure out later if a different approach needs to be taken.&lt;/p&gt;

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

&lt;p&gt;When migrating from Java to Rust, I had to revisit a lot of concepts regarding testing. I learn to be way more pragmatic when going too far or spending too much time creating complex setups for tests that in the end would not bring too much value when compared to one specific integration test.&lt;/p&gt;

&lt;p&gt;Learning another language also gives you the opportunity to learn new ways of doing things that you can apply in general. Today if I had to code in Java again, I would try to use way more the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Optional&lt;/code&gt; type that I used in the past. After seeing how it works in Rust, is something that I think I could benefit way more in Java today than just using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Rust is still a young language. I’m sure the testing approach still has a long way to evolve and in a few years, this post probably is going to seem outdated.&lt;/p&gt;

&lt;p&gt;My final message is that if you come from another language you probably know that you need to adapt to how the language works (or at least something in between). So you should do the same for the testing approach.&lt;/p&gt;

</description>
        <pubDate>Sun, 13 Sep 2020 12:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/testing-between-java-and-rust</link>
        <guid isPermaLink="true">https://mrcosta.github.io/testing-between-java-and-rust</guid>
        
        
        <category>rust, java, tests, testing, tdd, unit tests, test pyramid</category>
        
      </item>
    
      <item>
        <title>Rust releases for single and multiple targets with GitHub Actions</title>
        <description>
&lt;p&gt;&lt;a href=&quot;https://github.com/actions&quot;&gt;GitHub Actions&lt;/a&gt; has been growing at a fast pace and I’ve been using it in some pet projects. In a recent one, I tried the support for binary releases (CLI tools). Currently, the Infrastructure Rust team is also &lt;a href=&quot;https://blog.rust-lang.org/inside-rust/2020/04/07/update-on-the-github-actions-evaluation.html&quot;&gt;evaluating GitHub Actions&lt;/a&gt; so you expect support for different scenarios to be easy to setup.&lt;/p&gt;

&lt;p&gt;I had trouble finding good and detailed material about how to setup releases for multiple targets with Rust for small projects, so I decided to document it myself hoping that it can help others.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/marketplace&quot;&gt;GitHub Actions marketplace&lt;/a&gt; is full of different actions that combined can give you the same result. If you know another approach than the one here, please let me know.&lt;/p&gt;

&lt;h1 id=&quot;1--workflow-for-the-releases&quot;&gt;1- Workflow for the releases&lt;/h1&gt;

&lt;p&gt;This workflow was set up for a small project, so we decided not having too many different steps when creating a new release:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Create new branch from master&lt;/code&gt; —&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Open a PR&lt;/code&gt; —&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Merge and release&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Merge and release&lt;/code&gt; can be split into:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;code checkout&lt;/li&gt;
  &lt;li&gt;creating the binary&lt;/li&gt;
  &lt;li&gt;incrementing version and pushing new tag/create a release&lt;/li&gt;
  &lt;li&gt;uploading generated binary/binaries to the new release&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;2--releasing-binaries-for-a-single-linux-target&quot;&gt;2- Releasing binaries for a single Linux target&lt;/h1&gt;

&lt;p&gt;Releasing binaries for a single target is simple. The folder structure for our project is the following (check it out &lt;a href=&quot;https://github.com/mrcosta/alemanes/tree/master/.github/workflows&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-ssh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;project&lt;/span&gt;_folder&amp;gt;/.github/workflows
    &lt;span class=&quot;k&quot;&gt;ci&lt;/span&gt;.yml
    &lt;span class=&quot;k&quot;&gt;create&lt;/span&gt;_tag_and_release.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re familiar with GitHub workflows, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ci.yml&lt;/code&gt; is where we execute common Continuous Integration jobs like unit/integration tests. For most of my Rust projects, I usually run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo check&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo test&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo fmt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo clippy&lt;/code&gt;. You
can check what GitHub actions I use for running cargo commands and the entire file &lt;a href=&quot;https://github.com/mrcosta/alemanes/blob/master/.github/workflows/ci.yml&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Most of the times you want to release only when the other jobs are successful. In our case, it means that all jobs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ci.yml&lt;/code&gt; are passing. In our project we achieve this by using GitHub project’s settings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;go to your project’s main page&lt;/li&gt;
  &lt;li&gt;go to project &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Settings&lt;/code&gt; in the top menu&lt;/li&gt;
  &lt;li&gt;go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Branches&lt;/code&gt; in the left side menu&lt;/li&gt;
  &lt;li&gt;click on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add Rule&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;type a branch name pattern in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Branch name pattern&lt;/code&gt; (in my case it was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;tick the box &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Require status checks to pass before merging&lt;/code&gt; choosing the jobs that you want to make sure are green in order to make the branch “mergeable”&lt;/li&gt;
  &lt;li&gt;click on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Create&lt;/code&gt; to confirm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And since the tutorial is about creating releases, I’m going to focus on explaining only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_tag_and_release.yml&lt;/code&gt; file below:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build, bump tag version and release&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and Release&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build project&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cargo build --release --locked&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bump version and push tag/create release point&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;WITH_V&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bump_version&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upload binary to release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;target/release/alemanes&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;alemanes-linux-amd64&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ steps.bump_version.outputs.new_tag }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;overwrite&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file is going to be detailed in the next sections where I split the explanation for each block. I’m going to paste almost every block and explain it, but maybe you want to open the file in another tab in order to follow the explanation and compare to the entire file at the same time.&lt;/p&gt;

&lt;p&gt;If I don’t mention something it’s because there’s nothing special about it for our context, but probably it’s mandatory in order to make everything work.&lt;/p&gt;

&lt;h2 id=&quot;21-when-to-execute-the-release-workflow&quot;&gt;2.1 When to execute the release workflow&lt;/h2&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This workflow is going to be executed every time a commit is pushed on the master branch.&lt;/p&gt;

&lt;h2 id=&quot;22-release-job-and-its-steps&quot;&gt;2.2 Release job and its steps&lt;/h2&gt;

&lt;h3 id=&quot;221-job-header&quot;&gt;2.2.1 Job header&lt;/h3&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and Release&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name: Build and Release&lt;/code&gt; it’s the job’s name and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runs-on: ubuntu-latest&lt;/code&gt; it’s the used virtual machine platform.&lt;/p&gt;

&lt;h3 id=&quot;222-checkout-step&quot;&gt;2.2.2 Checkout step&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check out our project code using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;actions/checkout@v2&lt;/code&gt; in order to execute the next steps on it.&lt;/p&gt;

&lt;h3 id=&quot;223-build-and-create-a-binary-step&quot;&gt;2.2.3 Build and create a binary step&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build project&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cargo build --release --locked&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo build&lt;/code&gt; command that generates the project’s binary in release mode (with optimizations for the target platform).&lt;/p&gt;

&lt;h3 id=&quot;224-bump-version-and-push-tagcreate-release&quot;&gt;2.2.4 Bump version and push tag/create release&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bump version and push tag/create release point&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;WITH_V&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bump_version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It bumps the version and pushes a tag, creating a release for it using  &lt;a href=&quot;https://github.com/marketplace/actions/github-tag-bump&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/code&gt;&lt;/a&gt; action.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id: bump_version&lt;/code&gt; is where we can send information from the current step to the next one. We need it in order to say for which tag/release we’re uploading the binary file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;note&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/code&gt; action only works in Linux VMs. If you try to generate a single release for macOs you get: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;##[error]Container action is only supported on Linux&lt;/code&gt;. Fortunately, with extra steps, we can still make it work using the same idea for release for multiple targets that we’re going to set up later. I’ll add a proposed solution at the end of the tutorial.&lt;/p&gt;

&lt;h3 id=&quot;225-upload-binary-to-release&quot;&gt;2.2.5 Upload binary to release&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upload binary to release&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;target/release/alemanes&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;alemanes-linux-amd64&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ steps.bump_version.outputs.new_tag }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;overwrite&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Upload its binaries using the action &lt;a href=&quot;https://github.com/marketplace/actions/upload-files-to-a-github-release&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file: target/release/alemanes&lt;/code&gt; is the binary you want upload to the release (it can be any kind of file: e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tar.gz&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset_name: alemanes-linux-amd64&lt;/code&gt;: filename that is going to appear for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target/release/alemanes&lt;/code&gt; file in &lt;a href=&quot;https://github.com/mrcosta/alemanes/releases&quot;&gt;releases page&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag: ${{ steps.bump_version.outputs.new_tag }}&lt;/code&gt;: to get the tag info from the previous step saying which tag/release we’re updating the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;3--releasing-binaries-for-multiple-targets&quot;&gt;3- Releasing binaries for multiple targets&lt;/h1&gt;

&lt;p&gt;The main difference on releasing binaries for multiple targets is that we need two workflows: one to create a tag and &lt;a href=&quot;https://help.github.com/en/actions/reference/events-that-trigger-workflows#external-events-repository_dispatch&quot;&gt;dispatch a repository event&lt;/a&gt;. And another one to be triggered on every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag-created&lt;/code&gt; event dispatched by the first one.&lt;/p&gt;

&lt;p&gt;This is a different project, so we have a different folder structure (check it out &lt;a href=&quot;https://github.com/DadosAbertosDeFeira/leis-municipais/tree/master/.github/workflows&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-ssh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;project&lt;/span&gt;_folder&amp;gt;/.github/workflows
    &lt;span class=&quot;k&quot;&gt;ci&lt;/span&gt;.yml
    &lt;span class=&quot;k&quot;&gt;create&lt;/span&gt;_new_tag.yml
    &lt;span class=&quot;k&quot;&gt;release&lt;/span&gt;.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ci.yml&lt;/code&gt; is the same as we saw in &lt;a href=&quot;#2--releasing-binaries-for-a-single-linux-target&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The difference in the structure here is that releasing binaries for multiple targets requires a separated job to create a tag that is the same one used by Linux, Windows and macOS platforms.&lt;/p&gt;

&lt;p&gt;Since we’re going to execute jobs in different VMs for each platform, is not possible right now to share information about the newly created tag only using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag: ${{ steps.bump_version.outputs.new_tag }}&lt;/code&gt; between jobs running in different platforms.&lt;/p&gt;

&lt;h2 id=&quot;31-create-new-tag-and-dispatch-repository-event&quot;&gt;3.1 Create new tag and dispatch repository event&lt;/h2&gt;

&lt;p&gt;The previous problem is solved by a separated job (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_new_tag.yml&lt;/code&gt;) that creates a new tag and &lt;a href=&quot;https://github.com/marketplace/actions/repository-dispatch&quot;&gt;dispatch a repository event&lt;/a&gt;. This is the content of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_new_tag.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bump version, create new tag and release point&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;bump_version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bump version, create tag/release point&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bump version and push tag/create release point&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bump_version&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;WITH_V&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Repository dispatch tag created event&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;peter-evans/repository-dispatch@v1&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.REPO_ACCESS_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;event-type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tag-created&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;client-payload&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{&quot;new_version&quot;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;steps.bump_version.outputs.new_tag&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;}&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This job has 3 steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;checkout code&lt;/li&gt;
  &lt;li&gt;bump the version and push tag/create a release&lt;/li&gt;
  &lt;li&gt;dispatch a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag-created&lt;/code&gt; event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two steps was described previously &lt;a href=&quot;#22-release-job-and-its-steps&quot;&gt;here&lt;/a&gt;, so let’s focus on the third one:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Repository dispatch tag created event&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;peter-evans/repository-dispatch@v1&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.REPO_ACCESS_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;event-type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tag-created&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;client-payload&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{&quot;new_version&quot;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;steps.bump_version.outputs.new_tag&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;}&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uses: peter-evans/repository-dispatch@v1&lt;/code&gt; is the action that dispatchs the repository event and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;client-payload: &apos;{&quot;new_version&quot;: &quot;${{steps.bump_version.outputs.new_tag }}&quot;}&apos;&lt;/code&gt; is a evaluated json payload used by the action. In the end the payload could look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json=&quot;&gt;{
   &quot;new_version&quot;: &quot;v0.10.0&quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We dispatch this event(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;event-type: tag-created&lt;/code&gt;) from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_new_tag.yml&lt;/code&gt; including the newly created tag in its payload and other jobs can be executed upon this event.&lt;/p&gt;

&lt;h2 id=&quot;32-upload-binaries-to-the-newly-created-tag&quot;&gt;3.2 Upload binaries to the newly created tag&lt;/h2&gt;

&lt;p&gt;The second job, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;release.yml&lt;/code&gt;, is executed when this event of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag-created&lt;/code&gt; is dispatched and uses its received payload to identify the tag to upload binaries from differents platform to the &lt;a href=&quot;https://github.com/DadosAbertosDeFeira/leis-municipais/releases&quot;&gt;same release&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and upload binaries to release&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;repository_dispatch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tag-created&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and Release&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ matrix.os }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;artifact_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais-linux-amd64&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;macos-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;artifact_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais-macos-amd64&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build project&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cargo build --release --locked&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upload binary to release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;target/release/${{ matrix.artifact_name }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ matrix.asset_name }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ github.event.client_payload.new_version }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;33-when-to-execute-the-release-workflow&quot;&gt;3.3 When to execute the release workflow&lt;/h2&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;repository_dispatch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tag-created&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This workflow is going to be executed every time there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repository_dispatch&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag-created&lt;/code&gt;(in our case dispatched by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create_new_tag.yml&lt;/code&gt;)&lt;/p&gt;

&lt;h2 id=&quot;34-different-environments-to-run-the-release-job&quot;&gt;3.4 Different environments to run the Release job&lt;/h2&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and Release&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ matrix.os }}&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;artifact_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais-linux-amd64&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;macos-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;artifact_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;leis-municipais-macos-amd64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strategy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matrix&lt;/code&gt; means that you have more than &lt;a href=&quot;https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix&quot;&gt;one variation of environment&lt;/a&gt; to run your job in. Is like an array where each block inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include&lt;/code&gt; specifies one configuration. In our example is for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubuntu-latest&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;macos-latest&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arfifact_name&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset_name&lt;/code&gt; are also necessary for the next steps(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifact_name&lt;/code&gt; maybe could be omitted since they have the same value).&lt;/p&gt;

&lt;h2 id=&quot;35-release-job-and-its-steps&quot;&gt;3.5 Release job and its steps&lt;/h2&gt;

&lt;h3 id=&quot;351-checkout-and-build&quot;&gt;3.5.1 Checkout and build&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build project&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cargo build --release --locked&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is the same as we saw in &lt;a href=&quot;#222-checkout-step&quot;&gt;here&lt;/a&gt;. The difference is that all steps run for each different platform.&lt;/p&gt;

&lt;h3 id=&quot;352-upload-binary-to-release&quot;&gt;3.5.2 Upload binary to release&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upload binary to release&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;target/release/${{ matrix.artifact_name }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ matrix.asset_name }}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ github.event.client_payload.new_version }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/code&gt; action to upload the generated binaries to the created tag/release. The difference is that we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matrix&lt;/code&gt; context properties to differentiate between each platform:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file: target/release/${{ matrix.artifact_name }}&lt;/code&gt; is the generated binary that is going to be uploaded to the release&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset_name: ${{ matrix.asset_name }}&lt;/code&gt;: is the binary’s name that appears in the release page. Since we have two different platforms, we want to differentiate them for the users.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag: ${{ github.event.client_payload.new_version }}&lt;/code&gt;: is how we access the information received from the dispatched repository event. What matters here is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new_version&lt;/code&gt; property that contains the desired tag version to upload our binary files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, you should have something as we have in &lt;a href=&quot;https://github.com/DadosAbertosDeFeira/leis-municipais/releases&quot;&gt;our releases page&lt;/a&gt;. After downloading one of the binaries, you probably need to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod +x binary_file&lt;/code&gt; in order to execute it.&lt;/p&gt;

&lt;h1 id=&quot;4--conclusion&quot;&gt;4- Conclusion&lt;/h1&gt;

&lt;p&gt;The final set up of the workflow seems simple now, but it took some time to check how tags, versioning and releases work in GitHub. After that finding the actions that you need and at the same time associating the events that you need to run each workflow. Also stumbling in some workflow “limitations” like &lt;a href=&quot;https://github.community/t5/GitHub-Actions/Sharing-a-variable-between-jobs/m-p/39043#M3636&quot;&gt;how to pass data between different jobs&lt;/a&gt; and understanding how you can achieve the same result using a different approach.&lt;/p&gt;

&lt;h1 id=&quot;5--extras&quot;&gt;5- Extras&lt;/h1&gt;

&lt;h2 id=&quot;51-pull-request-events&quot;&gt;5.1 Pull request events&lt;/h2&gt;
&lt;p&gt;During the setup I also had tried with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull_request&lt;/code&gt; event:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And I learnt that means that this is going to make the workflow to be executed &lt;a href=&quot;https://developer.github.com/v3/activity/events/types/#pullrequestevent&quot;&gt;NOT just when the PR it’s merged&lt;/a&gt; into master but even when a pull request is created. I didn’t want that, so I removed.&lt;/p&gt;

&lt;h2 id=&quot;52-solving-the-releasing-binaries-for-a-single-target-for-windowsmacos-platforms&quot;&gt;5.2 Solving the releasing binaries for a single target for Windows/macOS platforms&lt;/h2&gt;

&lt;p&gt;As mentioned in &lt;a href=&quot;#224-bump-version-and-push-tagcreate-release&quot;&gt;one of the previous sections&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anothrNick/github-tag-action@1.17.2&lt;/code&gt; action only works in Linux VMs. Using the same approach that we used for multiple target releases, we could solve the problem for a single Windows release, per example, with something like (beware I didn’t test this workflow):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build, bump tag version and release&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;repository_dispatch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tag-created&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and Release&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;windows-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Checkout code&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build project&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cargo build --release --locked&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upload binary to release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;svenstaro/upload-release-action@v1-release&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;target/release/alemanes&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;asset_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;alemanes-linux-amd64&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ github.event.client_payload.new_version }}&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;overwrite&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sun, 17 May 2020 12:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/rust-releases-with-github-actions</link>
        <guid isPermaLink="true">https://mrcosta.github.io/rust-releases-with-github-actions</guid>
        
        
        <category>rust, ci, releases, targets, github actions, github</category>
        
      </item>
    
      <item>
        <title>Notes from Accelerate: Building and Scaling High Performing Technology Organizations</title>
        <description>&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://mrcosta.github.io/assets/images/books/accellerate-devops.jpg&quot; alt=&quot;accelerate devops&quot; width=&quot;200&quot; /&gt;
&lt;/p&gt;

&lt;h1 id=&quot;1-some-thoughts&quot;&gt;&lt;strong&gt;1. Some thoughts&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;It’s good to work in projects that use the latest practices applied by the industry, but sometimes that is not the case
and you have to sell this fish to your boss in order to change organization. Sometimes just changing processes for the
sake of trying to make the company is not enough, so have numbers and a whole book to prove their point with numbers
is something that makes you even more confident to purpose something at your workspace.&lt;/p&gt;

&lt;h1 id=&quot;2-what-they-found&quot;&gt;&lt;strong&gt;2. What they found&lt;/strong&gt;&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;velocity is designed to be used as a capacity planning tool (how long it will take to finish the tasks);&lt;/li&gt;
  &lt;li&gt;the measure should focus on outcomes, not output&lt;/li&gt;
  &lt;li&gt;we should measure: delivery lead time, deployment frequency, time to restore service and change fail rate.
    &lt;ul&gt;
      &lt;li&gt;delivery part of the lead time: the time it takes for work to be implemented, tested, and delivered.&lt;/li&gt;
      &lt;li&gt;product delivery lead time: the time it takes to go from code committed to code successfully running in production.&lt;/li&gt;
      &lt;li&gt;deployment frequency: a software deployment to production or to an app store.&lt;/li&gt;
      &lt;li&gt;how quickly can a service be restored?&lt;/li&gt;
      &lt;li&gt;what percentage of changes to production fail&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;software delivery performance impacts organizational performance and noncommercial performance.&lt;/li&gt;
  &lt;li&gt;the fact that software delivery performance matters provides a strong argument against outsourcing the development of software
that is strategic to your business.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;3-measuring-culture&quot;&gt;&lt;strong&gt;3. Measuring Culture&lt;/strong&gt;&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;basic assumptions are formed over time as members of a group or organizations make sense of relationships, 
events, and activities. And are things that we may find difficult to articulate.&lt;/li&gt;
  &lt;li&gt;values also influence group interactions and activities by establishing social norms, which shape
the actions of the group members and provide contextual rules.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;pathological&lt;/strong&gt; organizations are characterized by large amounts of fear and threat.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;bureaucratic&lt;/strong&gt; organizations protect departments. Those in the department want to maintain their
“turf”, insist on their rules, and generally do things by the book - their book.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;generative&lt;/strong&gt; organizations focus on the mission. How do we accomplish our goal? Everything is 
subordinated to good performance, to doing what we are supposed to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three characteristics of good information:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;it provides answers to the questions that the receiver needs to be answered&lt;/li&gt;
  &lt;li&gt;it’s timely&lt;/li&gt;
  &lt;li&gt;it is presented in such a way that it can be effectively used by the receiver&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good culture requires trust and cooperation, so it reflects the level of collaboration
and trust inside the organization. You need to have good information to make decisions and these
decisions can be easily reverted with the team is open and transparent rather than closed and hierarchical.&lt;/p&gt;

&lt;p&gt;Google found that “who is on a team matter less than how the team members interact, structure their work,
and view their contributions”. It comes down to team dynamics.&lt;/p&gt;

&lt;p&gt;In complex adaptive systems, accidents are almost never the fault of a single person. Rather, accidents
typically emerge from a complex interplay of contributing factors.&lt;/p&gt;

&lt;p&gt;To change the culture: start by changing how people behave, what they do.&lt;/p&gt;

&lt;h1 id=&quot;4-technical-practices&quot;&gt;&lt;strong&gt;4. Technical Practices&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Many Agile adoptions have treated technical practices as secondary as compared to the management and team practices. The
research shows that technical practices play a vital role in achieving these outcomes. The research also found that Continuous
Delivery has an impact on software delivery performance, organizational culture, and other outcome measures, such as team burnout
and deployment pain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuous Delivery&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Continuous Delivery is a set of capabilities that enable us to get changes of all kinds into production safely, quickly and 
sustainably:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;detect any issues quickly&lt;/li&gt;
  &lt;li&gt;cost of pushing individual changes is very low&lt;/li&gt;
  &lt;li&gt;should be possible to provide our environments from information stored in version control&lt;/li&gt;
  &lt;li&gt;when implemented correctly, the process of releasing new versions to users should be a routine activity that can be performed
on demand at any time.&lt;/li&gt;
  &lt;li&gt;reduce deployment pain and team burnout because it makes not to be a big-bang event every time that needs to be done and
can be done during working hours&lt;/li&gt;
  &lt;li&gt;teams that can choose their own tools based on what is best for the users of those tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They found that teams that did well at continuous delivery achieved the following outcomes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;strong identification with the organization your work for&lt;/li&gt;
  &lt;li&gt;a higher level of software delivery performance&lt;/li&gt;
  &lt;li&gt;lower change fail rates&lt;/li&gt;
  &lt;li&gt;a generative, performance-oriented culture
This means that investments in technology are also investments in people&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;41-the-impacts-of-continuous-delivery-on-quality&quot;&gt;4.1 The impacts of Continuous Delivery on Quality&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;in the quality and performance of applications&lt;/li&gt;
  &lt;li&gt;the percentage of time spent on rework or unplanned work&lt;/li&gt;
  &lt;li&gt;the percentage of time spent working on defects identified by the end users (it represents the quality)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Unplanned work&lt;/strong&gt;: “paying attention to the low fuel warning light on an automobile versus running out of gas on the highway”.
In the first case, the organization can fix the problem in a planned manner, without much urgency or disruption to other
scheduled work. In the second case, they must fix the problem in a highly urgent manner, often requiring all hands on deck –
for example, have six engineers drop everything and run down the highway with full gas cans to refuel a stranded truck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test data management&lt;/strong&gt;: successful teams had adequate test data to run their fully automated test suites and could acquire
test data for running automated tests on demand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trunk Based Development&lt;/strong&gt;: it was correlated more with high delivery performance. Teams had fewer than three active
branches. Teams working with short-lived branches perform better than the ones with longer-lived branches.&lt;/p&gt;

&lt;h1 id=&quot;5-architecture&quot;&gt;&lt;strong&gt;5. Architecture&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Employing the latest whizzy microservices architecture deployed on containers is no guarantee of higher
performance if you ignore these characteristics.&lt;/p&gt;

&lt;p&gt;High performers:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;we can do most of our testing without requiring an integrated environment&lt;/li&gt;
  &lt;li&gt;we can and do deploy or release our application independently of other applications/services it depends on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest contributors to continuous delivery:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;make large-scale changes without the permission of somebody outside the team&lt;/li&gt;
  &lt;li&gt;make large-scale changes without other teams having to change something&lt;/li&gt;
  &lt;li&gt;complete their work without telling other people from external teams&lt;/li&gt;
  &lt;li&gt;deploy and release the product without depending on others&lt;/li&gt;
  &lt;li&gt;testing on demand&lt;/li&gt;
  &lt;li&gt;perform deployment during normal business hours
In other words: architecture and teams are loosely coupled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When teams can decide which tools they use, it contributes to software delivery performance and, in turn, to organizational
performance. When the tools provided actually make life easier for the engineers who use them, they will adopt
them of their own free will. This is a much better approach than forcing them to use tools that have been chosen for the
convenience of other stakeholders.&lt;/p&gt;

&lt;h1 id=&quot;6-integrating-infosec-into-the-delivery-lifecycle&quot;&gt;&lt;strong&gt;6. Integrating infosec into the delivery lifecycle&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Build security from scratch, when is the best moment to do this kind of preparation. Building
security improves delivery performance because you spent less time remediating security
issues.&lt;/p&gt;

&lt;h1 id=&quot;7-management-practices-for-software&quot;&gt;&lt;strong&gt;7. Management practices for software&lt;/strong&gt;&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;limit work in progress&lt;/li&gt;
  &lt;li&gt;visual displays with productivity metrics and aligning them with operational goals&lt;/li&gt;
  &lt;li&gt;use data from the application to make business decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;high performers: peer review (with the team) instead of bureaucratic process with external entities.&lt;/p&gt;

&lt;h1 id=&quot;8-product-development&quot;&gt;&lt;strong&gt;8. Product Development&lt;/strong&gt;&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;user research from the very beginning of the product lifecycle.&lt;/li&gt;
  &lt;li&gt;use of MVPs&lt;/li&gt;
  &lt;li&gt;customer feedback&lt;/li&gt;
  &lt;li&gt;work (features) in small batches&lt;/li&gt;
  &lt;li&gt;update specifications without requiring the approval of people outside the team&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;9-making-work-sustainable&quot;&gt;&lt;strong&gt;9. Making Work Sustainable&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Deployment pain&lt;/strong&gt;: the fear and anxiety that engineers can feel when deploying something in production.
They find that where code deployments are most painful, you’ll find the poorest software delivery performance,
organizational performance, and culture. Deployments need to easily happen during normal business hours.
Build intelligence into the application and the platform so that the deployment process can be as simple as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Burnout&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;“learning from failure” kind of environment&lt;/li&gt;
  &lt;li&gt;communicating a strong sense of purpose&lt;/li&gt;
  &lt;li&gt;investing in employee development&lt;/li&gt;
  &lt;li&gt;asking employees what is preventing them from achieving their objectives&lt;/li&gt;
  &lt;li&gt;giving employees time, space, and resources to experiment and learn&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common problems that can lead to burnout&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;job demands exceed human limits&lt;/li&gt;
  &lt;li&gt;lack of control: inability to influence decisions that affect your job&lt;/li&gt;
  &lt;li&gt;insufficient rewards: financial, institutional, or social rewards&lt;/li&gt;
  &lt;li&gt;breakdown of community: unsupportive workplace environment&lt;/li&gt;
  &lt;li&gt;absence of fairness: lack of fairness in decision-making processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to reduce or fight burnout&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;strong feelings of burnout are found in organizations with a pathological, power-oriented culture. Create
a blame-free environment, striving to learn from failures, and communicating a shared sense of purpose.&lt;/li&gt;
  &lt;li&gt;deployment pain&lt;/li&gt;
  &lt;li&gt;the effectiveness of leaders&lt;/li&gt;
  &lt;li&gt;organizational investments in DevOps&lt;/li&gt;
  &lt;li&gt;organizational performance. When organizational values and individual values aren’t aligned, you are more
likely to see burnout in employees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;10-employee-satisfaction-identity-and-engagement&quot;&gt;&lt;strong&gt;10. Employee satisfaction, identity, and engagement&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;They found that employees in high-performing teams were 2.2 times more likely to recommend their organization
to a friend: highly engaged workers are associated with the high performers’ companies.&lt;/p&gt;

&lt;p&gt;When leaders invest in their best work, employees identify more strongly with the organization and are willing to go the
extra mile to help it be successful. In return, organizations get higher levels of performance and productivity,
which lead to better outcomes for the business.&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;Continuous Delivery  
                    --&amp;gt; Job Satisfaction --&amp;gt; Organisational Performance
Lean Practices
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;11-transformational-leadership&quot;&gt;&lt;strong&gt;11. Transformational Leadership&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;Good leaders affect a team’s ability to deliver code, architect good systems, and apply Lean principles to
how the team manages its work and develops products:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;establishing and supporting generative and high-trust cultural norms&lt;/li&gt;
  &lt;li&gt;creating technologies that enable developer productivity, reducing code deployment lead times and supporting more
reliable infrastructures&lt;/li&gt;
  &lt;li&gt;supporting team experimentation and innovation, and creating and implementing better products faster&lt;/li&gt;
  &lt;li&gt;working across organizational silos to achieve strategic alignment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leaders are those who set the tone of the organization and reinforce the desired cultural norms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Five characteristics of a transformational leader are&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;vision: understands where the organisation is going and where it should be&lt;/li&gt;
  &lt;li&gt;inspirational communication&lt;/li&gt;
  &lt;li&gt;intellectual stimulation: challenges followers to think about problems in new ways&lt;/li&gt;
  &lt;li&gt;supportive leadership: demonstrates care and consideration of followers personal needs and feelings&lt;/li&gt;
  &lt;li&gt;personal recognition: praises and acknowledges the achievement of goals and improvements in work quality; personally
compliments others when they do outstanding work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;111-other-things-to-create-a-good-environment&quot;&gt;11.1 Other things to create a good environment&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;establish a dedicated training budget and make sure people know about it&lt;/li&gt;
  &lt;li&gt;encourage staff to attend technical conferences at least once a year and summarize what they learned for the team&lt;/li&gt;
  &lt;li&gt;set-up internal hack days&lt;/li&gt;
  &lt;li&gt;set-up days to work on technical debt&lt;/li&gt;
  &lt;li&gt;set-up space to share knowledge&lt;/li&gt;
  &lt;li&gt;give time to experiment with new technologies&lt;/li&gt;
  &lt;li&gt;let the team choose their tools&lt;/li&gt;
  &lt;li&gt;make monitoring a priority: proactive monitoring was strongly related to performance and job satisfaction.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 01 May 2019 11:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2019-05-01-accelerate-devops</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2019-05-01-accelerate-devops</guid>
        
        
        <category>books</category>
        
        <category>devops</category>
        
        <category>practices</category>
        
        <category>culture</category>
        
      </item>
    
      <item>
        <title>Notes from Growing Object-oriented Software Guided by Tests</title>
        <description>&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://mrcosta.github.io/assets/images/books/growing.jpg&quot; alt=&quot;building microservices&quot; width=&quot;200&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;1-intro&quot;&gt;1. Intro&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;mock objects are substitute implementations for testing how an object interacts with its neighbors.&lt;/li&gt;
  &lt;li&gt;testing is no long just about keeping defects from the users; instead, it’s about helping the team to understand the features that the users
need and to deliver those features reliably and predictably.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“in our experience, dramatically improves the quality of the systems we build, in particular their reliability and their flexibility
in response to new requirements”&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;new applications can force developers into unfamiliar corners.&lt;/li&gt;
  &lt;li&gt;they all know there will be changes, they just don’t know what changes. They need a process that will help them cop with uncertainty
as their experience grows, to anticipate unanticipated changes.&lt;/li&gt;
  &lt;li&gt;iterative development progressively refines the implementation of features in response to feedback until they are good enough.&lt;/li&gt;
  &lt;li&gt;we need constant testing to catch regression errors, so we can add new features without breaking existing ones.&lt;/li&gt;
  &lt;li&gt;TDD turns testing into a design activity. We use the tests to clarify our ideas about what we want the code to do. It makes
code accessible for testing often drives it towards being cleaner and more modular.&lt;/li&gt;
  &lt;li&gt;the cycle of TDD: write a test; write some code to get it working; refactor the code to be as simple an implementation of the tested
features as possible. Repeat.&lt;/li&gt;
  &lt;li&gt;we use TDD to give us feedback on the quality of the implementation (“Does it work?”) and design (“Is it well structured?”).&lt;/li&gt;
  &lt;li&gt;writing tests:
    &lt;ul&gt;
      &lt;li&gt;makes us clarify the acceptance criteria for the next piece of work. We have to ask ourselves how we can tell when we’re done.&lt;/li&gt;
      &lt;li&gt;encourages us to write loosely coupled components, so they can easily be tested in isolation and, at higher levels, combined together (design)&lt;/li&gt;
      &lt;li&gt;adds an executable description of what the code does&lt;/li&gt;
      &lt;li&gt;adds to a complete regression suite (implementation)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;running tests:
    &lt;ul&gt;
      &lt;li&gt;detects errors while the context is fresh in our mind (implementation);&lt;/li&gt;
      &lt;li&gt;let us know when we’ve done enough, discouraging “gold plating” and unnecessary features (design)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;never write new functionality without a failing test.&lt;/li&gt;
  &lt;li&gt;they use acceptance tests (that exercises the system end-to-end in a environment that
tries to reflect the production environment), but personally I would no write a new acceptance test for each
new feature. I prefer writing this kind of test for journeys and invest in other kind of tests (like integration and contract tests).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;acceptance tests&lt;/strong&gt;: does the whole system work? It helps to speak with the domain experts (or Product Owners) and to make sure
that existing features haven’t broken.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;integration&lt;/strong&gt;: does our code work against code we can’t change?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;unit&lt;/strong&gt;: Do our objects do the right thing/Are they convenient to work with?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;external quality&lt;/strong&gt; and &lt;strong&gt;internal quality&lt;/strong&gt;: external quality is how well the sytem meets the needs of its customers and users
(is it functional, reliable, available, responsive, etc.). And internal quality is how well it meets the needs of its developers and
administrators (is it easy to understand, easy to change, etc).&lt;/li&gt;
  &lt;li&gt;end to end tests tells about the external quality and how the team understand the domain.&lt;/li&gt;
  &lt;li&gt;a class to be easy to unit-test must have explicit dependencies that can easily be substituted and clear responsibilities that
can easily be invoked and verified. Consequently loosely coupled and highly cohesive.&lt;/li&gt;
  &lt;li&gt;we’re tempted not to write tests when our code makes it difficult, but we try to resist. We use such difficulties as an opportunity
to investigate why the test is hard to write and refactor the code to improve its structure. We call this “listening to the tests”.&lt;/li&gt;
  &lt;li&gt;elements are coupled if a change in one forces a change in the other.&lt;/li&gt;
  &lt;li&gt;an element’s cohesion is a measure of whether its responsibilities form a meaningful unit. For example, a class that parses
both dates and URLs is not coherent, because they’re unrelated concepts. Think of a machine that washes both clothes and dishes - it’s
unlikely to do both well.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-test-driven-development-with-objects&quot;&gt;2. Test-Driven Development with Objects&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;object-oriented design focuses more on the communication between objects than on the objects themselves.&lt;/li&gt;
  &lt;li&gt;an object communicates by messages: it receives messages from other objects and reacts by sending messages to other objects as well,
as perhaps, returning a value or exception to the original sender. An object has a method of handling every type of message
that it understands and, in most cases, encapsulates some internal state that it uses to coordinate its communication with other objects.&lt;/li&gt;
  &lt;li&gt;this lets us change the behavior of the system by changing the composition of its objects-add and removing instances, plugging
different combinations together-rather than writing procedural code. The code we write to manage this composition is a declarative
definition of the how the web of objects will behave. It’s easier to change the sytem’s behavior because we can focus on
what we want it do, not how.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;tell, don’t ask&lt;/strong&gt;: use this “style” to avoid train wreck, where a series of getters is chained together like the carriages
in a train.&lt;/li&gt;
  &lt;li&gt;we should ask to the object the question we really want answered, instead of asking for the information to help us figure out
the answer ourselves.&lt;/li&gt;
  &lt;li&gt;adding a query method moves the behavior to the most appropriate object, gives it an explanatory name, and makes it easier to test.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;unit-testing-the-collaborating-objects&quot;&gt;unit-testing the collaborating objects&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;a circle object will send messages to one or more of its three neighbors when invoked. How can we test that it does so correctly
without exposing any of its internal state?&lt;/li&gt;
  &lt;li&gt;one option is to replace the target object’s neighbors in a test with substitutes, or mock objects. We can specify how we expect
the target object to communicate with its mock neighbors for a triggering event; we call these specifications &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expectations&lt;/code&gt;. During
the test, the mock objects assert that they have been called as expected; they also implement any stubbed behavior needed to make the
rest of the test work.&lt;/li&gt;
  &lt;li&gt;make clear the intention of every test: distinguish between the tested functionality, the supporting infrastructure, and the object
structure.&lt;/li&gt;
  &lt;li&gt;JUnit uses reflection to walk the structure of a class and run whatever it can find in that class that represents a test.&lt;/li&gt;
  &lt;li&gt;test fixtures: a fixture may be set up before the test runs and torn down after it has finished. Many tests don’t need 
tear down and it’s enough to just let the JVM garbage work.&lt;/li&gt;
  &lt;li&gt;test runners: in charge of running the tests. Per example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Parameterized&lt;/code&gt; test runner let you write data-driven tests in which
the same test methods are run for many different data values returned from a static method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-kick-starting-the-test-driven-cycle&quot;&gt;3. Kick-starting the Test-Driven Cycle&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;to run an initial end-to-end test that fails is already a lot of work. Deploying and testing right from the start of a project
forces the team to understand how their system fits into the world. It flushes out the “unknown unknown”.&lt;/li&gt;
  &lt;li&gt;we view feedback as a fundamental tool, and we want to know as early as possible whether we’re moving in the right direction. 
Once we have our fist test in place, the subsequent tests will be much quicker to write.&lt;/li&gt;
  &lt;li&gt;one of the symptons of an unstable development environment is that there’s no obvious first place to look when something fails.&lt;/li&gt;
  &lt;li&gt;a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;walking skeleton&lt;/code&gt; is an implementation of the thinnest possible slice of real functionality that we can automatically build,
deploy, and test end-to-end. “End-to-end” refers to the process, as well as the system. We want our test to start from scratch,
build a deployable system, deploy it into a production-like environment, and then run the tests through the deployed system.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;nothing forces us to understand a process better than trying to automate it&lt;/em&gt;. If it’s going to take six weeks to take six
weeks and four signatures to set up a database, we want to know now, not two weeks before delivery.&lt;/li&gt;
  &lt;li&gt;we make the smallest number of decisions we can to kick-start the TDD cycle, to allow us to start learning and improving from real
feedback.&lt;/li&gt;
  &lt;li&gt;no tests are perfect, of course, but in practice we’ve found that a substantial test suite allows us to make major changes safely.&lt;/li&gt;
  &lt;li&gt;the time to implement the first few features will be unpredictable as the team discovers more about its requirements and target environment.&lt;/li&gt;
  &lt;li&gt;incremental development can be disconcerting for teams and management who aren’t used to it because it front-loads the stress in a project.
Projects with late integration start calmly but generally turn difficult towards the end as the team tries to pull the system together for
the first time. Late integration is unpredictable because the team has to assemble a great many moving parts with limited time and budget
to fix any failures. The result is that experienced stakeholders react badly to the instability at the start of an incremental project
because they expect that the end of the project will be much worse. Our experience is that a well-run incremental development runs in the
opposite direction. It starts unsettled but then, after a few features have been implemented and the project automation has been built up,
settles in to a routine. As project approaches delivery, the end-game should be a steady production of functionality, perhaps with
a burst of activity before the first release. All the mundane but brittle tasks, such as deployment and upgrades, will have been
automated so that they “just work”.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-maintaining-the-test-driven-cycle&quot;&gt;4. Maintaining the Test-Driven Cycle&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;writing the tests before coding makes us clarify what we want to achieve. It makes us look at the system from the user’s
point of view, understanding what they need it to do rather than speculating about features from the implementers’ point of view.&lt;/li&gt;
  &lt;li&gt;we prefer to start by testing the simplest success case. Once that’s working, we’ll have a better idea of the real structure
of the solution and can prioritize between handling any possible failures we noticed along the way and further success cases. Of course,
a feature isn’t complete until it’s robust. This isn’t an excuse not to bother with failure handling-but we can choose when
we want to implement first.&lt;/li&gt;
  &lt;li&gt;we discover that these objects need supporting services from the rest of the system to perform their responsibilities. We write more
objects to implement these services, and discover what services these new objects need in turn.&lt;/li&gt;
  &lt;li&gt;when we find a feature that’s difficult to test, we don’t just ask ourselves how to test it, but also why is it difficult to test.
The same structure that makes the code difficult to test now will make it difficult to change in the future.&lt;/li&gt;
  &lt;li&gt;if we just test at too fine a grain, we’ll miss problems that arise from objects not working together.&lt;/li&gt;
  &lt;li&gt;how much unit testing should we do, using mock objects to break external dependencies, and how much integration testing? We
don’t think there’s a single answer to this question. It depends too much on the context of the team.&lt;/li&gt;
  &lt;li&gt;The best we can get from the testing part of TDD, is the confidence that we can change the code without breaking it: Fear kills
progress. The trick is to make sure that the confidence is justified.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;5-object-oriented-style&quot;&gt;5. Object-Oriented Style&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;we value code that is easy to maintain over code that is easy to write. Implementing a feature in the most direct way can damage
the maintainability of the system, for example by making the code difficult to understand or by introducing hidden dependencies
between components. Balancing immediate and longer-term concerns is often tricky, but we’ve seen too many teams that can no long
deliver because their system is too brittle.&lt;/li&gt;
  &lt;li&gt;change as little code as possible. If all the relevant changes are in one area of code, we don’t have to hunt around the system
to get the job done.&lt;/li&gt;
  &lt;li&gt;high level abstractions: that’s why most people order food from a menu in terms of dishes, rather than detail the recipes used to create them.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ports and adapters&lt;/strong&gt;: the code for the business domain is isolated from its dependencies on technical infrastructure, such
as databases and user interfaces. We don’t want technical concepts to leak into the application model, so we write interfaces
to describe its relationships with the outside world in its terminology.&lt;/li&gt;
  &lt;li&gt;features without side effects mean that we can assemble our code from smaller components, minimizing the amount of
risky shared state. We find that a little immutability within the implementation of a class leads to much safer code and that,
if we do a good job, the code reads well too.&lt;/li&gt;
  &lt;li&gt;our heuristic is that we should be able to describe what an object does without using any conjunctions (“and”, “or”).&lt;/li&gt;
  &lt;li&gt;the API of a composite object should not be more complicated than that of any of its components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;6-achieving-object-oriented-design&quot;&gt;6. Achieving Object-Oriented Design&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;first, starting with a test means that we have to describe what we want to achieve before we consider how. This focus
helps us maintain the right level of abstraction for the target object. If the intention of the unit test is unclear then
we’re probably mixing up concepts and not ready to start coding. It also helps us with information hiding as we have to
decide what needs to be visible from outside the object. Third, to construct an object for a unit test, we have to pass its
dependencies to it, which means that we have to know what they are. This encourages context independence, since we have
to be able to set up the target object’s environment before we can unit-test it. A unit test is just another context. We’ll
notice that an object with implicit (or just too many) dependencies is painful to prepare for testing and make a point of cleaning
it up.&lt;/li&gt;
  &lt;li&gt;we think the communication patterns between objects are more important.&lt;/li&gt;
  &lt;li&gt;an interface describes whether two components will fit together, while a protocol describes whether they will work together.&lt;/li&gt;
  &lt;li&gt;we use tdd wih mock objects as a technique to make these communication protocols visible, both as a tool for discovering them
during development and as a description when revisiting the code.&lt;/li&gt;
  &lt;li&gt;when starting a new area of code, we might temporarily suspend our design judgment and just write code without attempting to impose
much structure. This allows us to gain some experience in the area and test our understanding of any external APIs we’re developing
against. Splitting out a new object also forces us to look at the dependencies of the code we’re pulling out.&lt;/li&gt;
  &lt;li&gt;under time pressure, it’s tempting to leave the unstructured code as is and move on to the next thing (“after all, it works and
it’s just one class…”). We’ve seen too much code where the intention wasn’t clear and the cost of cleanup kicked in when the
team could least afford it.&lt;/li&gt;
  &lt;li&gt;we might be adding behavior to an object and find that, following our design principles, some new feature doesn’t belong inside it.&lt;/li&gt;
  &lt;li&gt;we give the new service a name and mock it out in the client object’s unit tests, to clarify the relationship between the two. Then
we write an object to provide that service and, in doing so, discover what services that object needs. We follow this chain (or perhaps
a directed graph) of collaborator relationships until we connect up to existing objects, either our own or from a third-party API.&lt;/li&gt;
  &lt;li&gt;when the test for an object becomes too complicated to set up when there are too many moving parts to get the code into the relevant
state, consider bundling up some of the collaborating objects.&lt;/li&gt;
  &lt;li&gt;we use interfaces to name the roles that objects can play and to describe the messages they’ll accept.&lt;/li&gt;
  &lt;li&gt;the fewer methods there are on an interface, the more obvious is its role in the calling object. We don’t have to worry which
other methods are relevant to a particular call and which were included for convenience. Narrow interfaces are also easier
to write adapters and decorators for; there’s less to implement, so it’s easier to write objects that compose together well.&lt;/li&gt;
  &lt;li&gt;driving an interface from its client avoids leaking excess information about its implementers, which minimizes any
implicit coupling between objects and so keeps the code malleable.&lt;/li&gt;
  &lt;li&gt;if there really isn’t a good implementation name, it might mean that the interface is poorly named or designed. Perhaps it’s
unfocused because it has too many responsibilities; or it’s named after its implementation rather than its role in the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;7-building-on-third-party-code&quot;&gt;7. Building on Third-Party code&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;only mock types that you own - don’t mock types you can’t change&lt;/li&gt;
  &lt;li&gt;although we know how we want our abstraction to behave, we don’t know if it really does so until we test it in combination with the third-party code.&lt;/li&gt;
  &lt;li&gt;providing mock implementations of third-party types is of limited use when unit-testing the objects that call them.&lt;/li&gt;
  &lt;li&gt;a second risk is that we have to be sure that the behavior we stub or mock matches what the external library will actually do. How difficult this is
depends on the quality of the library. Whether it’s specified (and implemented) well enough for us to be certain that our unit tests are valid.
Even if we get it right once, we have to make sure that the tests remain valid when we upgrade the libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;write-an-adapter-layer&quot;&gt;write an adapter layer&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;if we don’t want to mock an external API, how can we test the code that drives it? We will have used TDD to design interfaces for the services our
objects need – which will be defined in terms of our objects domain, not the external library.&lt;/li&gt;
  &lt;li&gt;we write a layer of adapter objects that uses the third party API to implement these interfaces. We keep this layer as thin as possible, to minimize
the amount of potentially brittle and hard-to-test code. We test these adapters with focused integration tests to confirm our understanding of how the
third party API works. There will be relatively few integration tests compared to the number of unit tests, so they should not get in the way of the build
even if they’re not as fast as the in-memory unit tests.&lt;/li&gt;
  &lt;li&gt;following this approach consistently produces a set of interfaces that define the relationship between our application and the rest of the world
in our application’s terms and discourages low-level technical concepts from leaking into the application domain model.&lt;/li&gt;
  &lt;li&gt;there are some exceptions where mocking third-party libraries can be helpful. We might use mocks to simulate behavior that is hard to trigger with
the real library, such as throwing exceptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;8-a-worked-example&quot;&gt;8. A Worked Example&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;even the best people misunderstand requirements and technologies or, sometimes, just miss the point. A resilient process allows
for mistakes and includes techniques for discovering and recovering from errors as early as possible.&lt;/li&gt;
  &lt;li&gt;focus on just the immediate change at hand and merging changes back in is never a crisis.&lt;/li&gt;
  &lt;li&gt;we’ve often found it worth writing a small amount of ugly code and seeing how it falls out. It helps us to test our ideas
before we’ve gone too far, and sometimes the results can be surprising. The important point is to make sure we don’t leave it ugly.&lt;/li&gt;
  &lt;li&gt;there are teams that overdo their design effort, but our experience is that most teams spend too little time clarifying the code
and pay for it in maintenance overhead.&lt;/li&gt;
  &lt;li&gt;we try to minimize the time when we have code that does not compile by keeping changes incremental.&lt;/li&gt;
  &lt;li&gt;we’re grow our a design from what looks like an unpromising start. We alternate, more or less, between adding features
and reflecting on - and cleaning up - the code that results. The cleaning up stage is essential, since without it we would end up
with an unmaintainable mess. We’re prepared to defer refactoring code if we’re not yet clear what to do, confident that we will take
the time when we’re ready. In the meantime, we keep our code as clean as possible, moving in small increments and using techniques
such as null implementation to minimize the time when it’s broken.&lt;/li&gt;
  &lt;li&gt;we’re try hard to follow what the code is telling us instead of imposing our preconceptions.&lt;/li&gt;
  &lt;li&gt;we discover that some of the choices we made are no longer valid, so we dare to change existing code. We continue to refactor
and sense that a more interesting structure is starting to appear.&lt;/li&gt;
  &lt;li&gt;nothing shakes out a design like trying to implement it, and between us we know just a handful of people who are smart enough to get
their designs always right. Our coping mechanism is to get into the critical areas of the code early and to allow ourselves to change
our collective mind when we could do better. We rely on our skills, on taking small steps, and on the tests to protect us when we
make changes.&lt;/li&gt;
  &lt;li&gt;deciding when to change the design requires a good sense for tradeoffs, which implies both sensitivity and technical maturity:
“I’m about to repeat this code with minor variations, that seems dull and wasteful” as against “This may not be the right time to
rework this, I don’t understand it yet”.&lt;/li&gt;
  &lt;li&gt;as we learn more about what the structure should be by using the code we’ve written, we learn more about the names we’ve chosen
when we work with them.&lt;/li&gt;
  &lt;li&gt;draw something when you don’t know exactly where to start.&lt;/li&gt;
  &lt;li&gt;The skill is in learning how to divide requirements up into incremental slices, always having something working, always adding just
one more feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;9-listening-to-the-tests&quot;&gt;9. Listening to the Tests&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;when writing a test is hard, it can means that your design can be improved.&lt;/li&gt;
  &lt;li&gt;we’ve found that a object easy to test is also easy to change.&lt;/li&gt;
  &lt;li&gt;TDD is also about feedback on the code’s internal qualities: the coupling and cohesion of its classes, dependencies that
are explicit or hidden, and effective information hiding.&lt;/li&gt;
  &lt;li&gt;we don’t just ask ourselves how to test it, but also why is it difficult to test.&lt;/li&gt;
  &lt;li&gt;instead of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Date&lt;/code&gt; directly we introduce &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clock&lt;/code&gt; and pass it into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Receiver&lt;/code&gt; class.&lt;/li&gt;
  &lt;li&gt;tests for supportive logging: protect us from breaking any tools and scripts that other people write to analyze them.&lt;/li&gt;
  &lt;li&gt;tests for diagnostic logging: not necessarily tested.&lt;/li&gt;
  &lt;li&gt;clients should not be forced to depend upon interfaces that they do not use, but that’s exactly what we do when we mock
a concrete class.&lt;/li&gt;
  &lt;li&gt;interfaces give us better information-hiding and clearer abstractions.&lt;/li&gt;
  &lt;li&gt;once a codebase starts to “rot”, the developers will be under pressure to botch the code to get the next job done. It
doesn’t take many such episodes to dissipate a team’s good intentions.&lt;/li&gt;
  &lt;li&gt;test names should act as documentation for the code.&lt;/li&gt;
  &lt;li&gt;AAA: arrange, act and assert.&lt;/li&gt;
  &lt;li&gt;all code should emphasize &lt;strong&gt;“what”&lt;/strong&gt; it does over &lt;strong&gt;“how”&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;our highest concern is making the test describe what the target code does, so we refactor enough to be able to see its
flow.&lt;/li&gt;
  &lt;li&gt;write test data builders&lt;/li&gt;
  &lt;li&gt;allocate literal values to variables and constants with names that describe their function.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;10-test-diagnostics&quot;&gt;10. Test Diagnostics&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;a “failing” test has succeeded at the job it was design to do, but it needs to be clear about the failure’s reason.&lt;/li&gt;
  &lt;li&gt;sometimes is quicker to roll back and restart with a clear head than to keep digging.&lt;/li&gt;
  &lt;li&gt;the tests overspecify the expected behavior of the target code, constraining it more than necessary.&lt;/li&gt;
  &lt;li&gt;mind methods returning null to other objects since null can be used as a return of anything. So if you’re mocking something
make sure that is returning the right thing rather than just forcing a “null” return.&lt;/li&gt;
  &lt;li&gt;use expressive assertions.&lt;/li&gt;
  &lt;li&gt;commands have side effects, queries don’t.&lt;/li&gt;
  &lt;li&gt;high level tests to make sure that everything works together.&lt;/li&gt;
  &lt;li&gt;make sure every test starts with the database in a known, clean state.&lt;/li&gt;
  &lt;li&gt;ORM mappings can by declarative or configuration, but misconfiguration creates defects that are difficult to
diagnose, so we use round-trip tests so we can quickly identify the cause of such defects.&lt;/li&gt;
  &lt;li&gt;tests with realistic infrastructure are slower than with in memory database. We also can unit-test our code
by defining a clean interface to the persistence infrastructure.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 21 Feb 2019 11:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2019-02-21-growing-object-oriented</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2019-02-21-growing-object-oriented</guid>
        
        
        <category>books</category>
        
        <category>object oriented</category>
        
        <category>tests</category>
        
        <category>test driven development</category>
        
      </item>
    
      <item>
        <title>Notes from Building Microservices</title>
        <description>&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://mrcosta.github.io/assets/images/books/building_microservices.jpg&quot; alt=&quot;building microservices&quot; width=&quot;200&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;1-microservices&quot;&gt;1. Microservices&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Domain-driven design, continuous delivery, on demand virtualization, infrastructure automation, small autonomous teams and
systems at scale: microservices have emerged from this world.&lt;/li&gt;
  &lt;li&gt;in a monolithic system we try to make sure that our code is cohesive, trying to group code together (single responsibility principle).&lt;/li&gt;
  &lt;li&gt;small and autonomous services that work together.&lt;/li&gt;
  &lt;li&gt;microservices is also focus in high cohesion. It focus service boundaries on business boundaries, making it obvious
where code lives for a given piece of functionality. And keeping it focused we avoid the temptation to grow it large.&lt;/li&gt;
  &lt;li&gt;the rule of thumb gave in the book is that a microservice could be rewritten in two weeks.&lt;/li&gt;
  &lt;li&gt;if a team is small, breakdown into microservices can be very sensible&lt;/li&gt;
  &lt;li&gt;microservice it’s a separate entity. We try to avoid packing multiple services onto the same “machine”&lt;/li&gt;
  &lt;li&gt;all communication between the services themselves are via network calls, to enforce separation between the services and tight coupling.&lt;/li&gt;
  &lt;li&gt;these services need to be able to change independently of each other, and be deployed by themselves without requiring consumers to change.&lt;/li&gt;
  &lt;li&gt;our services exposes an application programming interface (API), and collaborating services communicate with us via those APIs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;the golden rule&lt;/strong&gt;: can you make a change to a service and deploy it by itself without changing anything else?&lt;/li&gt;
  &lt;li&gt;if one part of our system needs to improve its performance, we might decide to use a different technology and this is easy to
approach with a microservices architecture than with a monolith.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;resilience&lt;/strong&gt;: if one component of a system fails, but that failures doesn’t cascade, you can isolate the problem and the rest of the system
can carry on working.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;scaling&lt;/strong&gt;: we can just scale those services that need scaling, allowing us to run other parts of the system on smaller, less powerful
hardware.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ease of deployment&lt;/strong&gt;: a one-line change to a big codebase requires the whole application to be deployed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;composability&lt;/strong&gt;: with microservices, think of us opening up seams in our system that are addressable by outside parties. 
As circumstances change, we can build things in different ways. With our services being in small size, the cost to replace
them with a better implementation, or even delete them altogether is easier to manage.&lt;/li&gt;
  &lt;li&gt;you should think of microservices as a specific approach for SOA&lt;/li&gt;
  &lt;li&gt;you’ll have to get much better at handling deployment, testing, and monitoring to unlock the benefits we’ve covered so far.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;shared-libraries&quot;&gt;Shared libraries&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;you lose true technology heterogeneity. The library typically has to be in the same language, or at the very least run on the same platform.&lt;/li&gt;
  &lt;li&gt;unless you’re using dynamically linked libraries, you cannot deploy a new library without redeploying the entire process, so your
ability to deploy changes in isolation is reduced.&lt;/li&gt;
  &lt;li&gt;you’ll find yourself creating code for common tasks that aren’t specific to your business domain that you want to reuse across
the organization, which is an obvious candidate for becoming reusable library.&lt;/li&gt;
  &lt;li&gt;shared code used to communicate between services can become a point of coupling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-the-evolutionary-architect&quot;&gt;2. The Evolutionary Architect&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;the architecture needs to make sure we have a joined-up technical vision, one that should help us deliver the system
our customers need.&lt;/li&gt;
  &lt;li&gt;bridges and buildings will fall down much less than the number of times our programs will crash, making comparisons
with engineers quite unfair.&lt;/li&gt;
  &lt;li&gt;our architecture needs to shift their thinking away from creating the perfect end product, and instead focus on helping create a
framework in which the right systems can emerge, and continue to grow as we learn more.&lt;/li&gt;
  &lt;li&gt;architecture have a duty to ensure that the system is habitable for developers too.&lt;/li&gt;
  &lt;li&gt;you may be OK with a team picking a different technology in a area of the system that they own.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“be worried about what happens between the boxes, and be liberal in what happens inside”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;strategic goals should focus in making the customers happy: &lt;em&gt;“let the customer achieve as much as possible using self-service”&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;principles&lt;/strong&gt;: rules you have made in order to align with a goal: if a goal is to decrease time to market, so you may define that teams will have full control over the lifecycle, 
independently of any other team.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;practices&lt;/strong&gt;: how we ensure the principles are being carried out: all logs need to be centralized; HTTP/REST is the standard integration style.&lt;/li&gt;
  &lt;li&gt;the principles between a Java and a .NET team can be equal, but the practices different. You can have some documentation around principles and practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://mrcosta.github.io/assets/images/books/goals-principles-practices.png&quot; alt=&quot;principles and goals&quot; width=&quot;400&quot; /&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;what we need to ensure that one bad service doesn’t bring down the whole system?&lt;/li&gt;
  &lt;li&gt;we need to find the balance between autonomy of the service without losing sight of the bigger picture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;other-aspects-of-microservices&quot;&gt;Other aspects of microservices&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;ensure that all services emit health and general monitoring metrics in the same way (push data into a central location or some polling system).&lt;/li&gt;
  &lt;li&gt;if you pick HTTP/REST, are you going to handle pagination and versioning?&lt;/li&gt;
  &lt;li&gt;ensure that our services shield themselves from unhealthy, downstream calls.&lt;/li&gt;
  &lt;li&gt;write good documentation with examples in order to expose your service.&lt;/li&gt;
  &lt;li&gt;what if the developers had a template to implement core attributes that each service needs? (some of the practices already in place).&lt;/li&gt;
  &lt;li&gt;if a lot of exceptions happen around the principles/practices, then we can change to reflect a new understand of it.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;I often take the approach that I should go with the group decision&lt;/em&gt;. Even that this means going with a decision that you don’t agree with.&lt;/li&gt;
  &lt;li&gt;the team needs to understand the vision themselves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;how-to-model-services&quot;&gt;How to model services&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;*what the world stood? On a tortoise. And what does the tortoise stand? On another tortoise.”&lt;/li&gt;
  &lt;li&gt;a change to one service should not require a change to another.&lt;/li&gt;
  &lt;li&gt;we want to limit the number of calls from one service to another, because beyond the potential performance problem, chatty communication
can lead to tight coupling.&lt;/li&gt;
  &lt;li&gt;related behavior sit together and unrelated behavior sit elsewhere.&lt;/li&gt;
  &lt;li&gt;each bounded context has an explicit interface. There is an internal-only representation, and the external representation we expose.&lt;/li&gt;
  &lt;li&gt;premature decomposing can be costly if you’re new to the domain. Break a monolith is easier than going microservices from day one.&lt;/li&gt;
  &lt;li&gt;you need to think about bounded contexts from a capability perspective and not about data that is shared.&lt;/li&gt;
  &lt;li&gt;if a new field is added to a piece of data, existing costumers shouldn’t be impacted.&lt;/li&gt;
  &lt;li&gt;any technology that push to expose internal representation should be avoided.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;shared database&lt;/strong&gt;: we’re allowing services to view and bind to internal implementation details and tight to all of them to one 
specific technology&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;communication&quot;&gt;Communication&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;synchronous: it blocks the operation until is complete&lt;/li&gt;
  &lt;li&gt;synchronous: doesn’t wait for the operation be complete and may not even care if it was complete or not&lt;/li&gt;
  &lt;li&gt;with an event-based collaboration, we invert things. Instead of a client initiating requests asking for things to be done, it instead says
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this thing happened and expects other parties to know what to do&lt;/code&gt;. You can just add subscribe to these events.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;orchestration vs choreography&lt;/strong&gt;: with orchestration we rely on a central brain to guide and drive the process, much like the conductor
in a orchestra. With choreography, we inform each part ot its job, and let it work out the details.&lt;/li&gt;
  &lt;li&gt;you need to be aware of orchestration, because you can end up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;god services&lt;/code&gt; communicating too much with other services.&lt;/li&gt;
  &lt;li&gt;with choreography you need extra work to ensure that you can monitor that the right things have happened.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;I strongly prefer aiming for a choreographed system, where each service is smart enough to understand its role in the whole dance&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;the client has to understand the semantics of the API in much the same way as a human being needs to understand that on a shopping
website the cart is where the items to be purchased will be.&lt;/li&gt;
  &lt;li&gt;provide links to allow consumers to navigate in the API endpoints (HAL standard per example).&lt;/li&gt;
  &lt;li&gt;for choreography: message brokers. And use dead-letter-queues to retry messages in another time.&lt;/li&gt;
  &lt;li&gt;have a good monitoring and consider the use of correlation IDs, which allow you to trace requests across process boundaries.&lt;/li&gt;
  &lt;li&gt;rather than make code shared, the company copies it for every new service to ensure that coupling doesn’t leak in. The evils
of too much coupling between services are far worse than the problems caused by code duplication. For logging libraries is ok, since
is not related with domain logic.&lt;/li&gt;
  &lt;li&gt;the best way to reduce impact of making breaking changes, is to avoid making them in the first place.&lt;/li&gt;
  &lt;li&gt;MAJOR change contains incompatible changes; MINOR new functionality but still compatible and PATCH just for bug fixes.&lt;/li&gt;
  &lt;li&gt;keep more than one version running and stop it when all the services migrated to the new one.&lt;/li&gt;
  &lt;li&gt;the longer it takes to these services to update, you should look to coexist different endpoints in the same microservice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-microservices-and-ui&quot;&gt;3. Microservices and UI&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;users don’t want to feel that different parts of the interface work in different ways.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;backend for frontends&lt;/strong&gt;: it can handle multiple backend calls and aggregate content if needed. This can lead to everything
being thrown in together, and suddenly we start to lose isolation of our various user interfaces, limiting our ability to release them
independently. It should contain behavior specific to delivering a particular user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-splitting-the-monolith&quot;&gt;4. Splitting the Monolith&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;identify the boundaries in our code.&lt;/li&gt;
  &lt;li&gt;the packages should interact in the same way the real-life organizational groups in our domain interact.&lt;/li&gt;
  &lt;li&gt;split as you go: think about where you are going to get the most benefit from some part of the codebase being separated. Other criterias:
areas that demands more frequent changes; or team location (different countries); technology&lt;/li&gt;
  &lt;li&gt;sometimes making one thing slower in exchange for other things is the right thing to do, specially if slower is still acceptable.&lt;/li&gt;
  &lt;li&gt;sometimes the system will change because some concept that was not there before had a need and then it was “borned”.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;eventual consistency&lt;/strong&gt;: we accept that the system will get itself into a consistent state at some point in the future. Or we can just
revert the transaction and try again.&lt;/li&gt;
  &lt;li&gt;be aware of report generation: some calls can require big amounts of data. &lt;strong&gt;Data pumbs&lt;/strong&gt;: push data to the report system using the database
of each microservice. We can push to this system as soon we see that an event happened (a user created per example). Or we can go
towards eventing system capable of routing our data to multiple different places depending on need.&lt;/li&gt;
  &lt;li&gt;when trying to figure out the impact of a change: what calls get made? Is there any circular references? Do you see two services
that are overly chatty? (this can indicate that they should be just one).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;5-deployment&quot;&gt;5. Deployment&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;is good to have the entire path to production to see the quality of our software and to reduce the time
take between releases, as we have one place to observe our build and releases process.&lt;/li&gt;
  &lt;li&gt;have pre-baked images with already installed dependencies to run the service.&lt;/li&gt;
  &lt;li&gt;install the configuration of the services in the source control.&lt;/li&gt;
  &lt;li&gt;the more your configuration changes, the more you will find problems only in certain environments.&lt;/li&gt;
  &lt;li&gt;be aware in how to handle sensitive information (credentials per example).&lt;/li&gt;
  &lt;li&gt;carefully when deploying different services at the same host. This way you’re not 100% making them separated, since an
overload in one service can compromise the resources for the other services. An outage to one host should impact only a single service.&lt;/li&gt;
  &lt;li&gt;can you write a line of code to launch a virtual machine, or shut one down? Can you deploy the software you have written
automatically? Can you deploy database changes without manual intervention? Embracing a culture of automation is key if you want
to keep the complexities of microservice architectures in check.&lt;/li&gt;
  &lt;li&gt;use containers: one host, multiple containers with one service each.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;6-deployment&quot;&gt;6. Deployment&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;you will want tests of different scope for different purposes.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;“we decide that from a feedback point of view we had way too many service and end-to-end tests”&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;mountbank to stube calls to other systems&lt;/li&gt;
  &lt;li&gt;as test scope increases, so too does the number of moving parts. A test can fail because some service is down, and this
is not related to the nature of the test itself. If you have tests that sometimes fails, but everyone just re-runs them because
they may pass again later, then you have flaky tests.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;normalization of deviance&lt;/strong&gt;: the idea that over time we can become so accustomed to things being wrong that we start to accept them
as being normal and not a problem.&lt;/li&gt;
  &lt;li&gt;not shared end-to-end tests: everyone is going to assume it is someone else’s problem.&lt;/li&gt;
  &lt;li&gt;if the same feature is covered in 20 different tests, perhaps we can get rid of half of them.&lt;/li&gt;
  &lt;li&gt;with a long test suite, any breaks take a while to fix. And while a broken integration test stage is being fixed, more changes
from upstream teams can pile in.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TEST JOURNEYS, NOT STORIES&lt;/strong&gt;. High value interactions and very few in number.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;consumer-driven tests to the rescue&lt;/strong&gt;: we don’t want our changes to break consumers. We are defining the expectations of
a consumer on a service (or producer). The expectations of the consumers are captured in code form as tests, which are then run
against the producer. If done right, these CDCs should be run as part of the CI build of the producer, ensuring that it never gets
deployed if it breaks on of these contracts.&lt;/li&gt;
  &lt;li&gt;on the producer side, you then verify that this consumer specification is met by using the JSON Pact specification to drive call
against your API and verify responses.&lt;/li&gt;
  &lt;li&gt;these end-to-end tests may form a useful safety net, where you are trading off cycle time for decreased risk. But be aware
that you will not eliminate all sources of defects.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;smoke test suite&lt;/strong&gt;: a collection of tests designed to be run against newly deployed software to confirm that the deployment worked.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;blue green deployment&lt;/strong&gt;: by keeping the old version running while we perform our release we greatly reduce the downtime associated
with releasing our software.&lt;/li&gt;
  &lt;li&gt;create a good process to revert code from a new deployment and back to a previous version.&lt;/li&gt;
  &lt;li&gt;execute performance tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;7-monitoring&quot;&gt;7. Monitoring&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;at bare minimum, monitore the response time of the service&lt;/li&gt;
  &lt;li&gt;number of errors&lt;/li&gt;
  &lt;li&gt;central aggregations for logs and metrics&lt;/li&gt;
  &lt;li&gt;are we reaching out limit? How long until we need more hosts?&lt;/li&gt;
  &lt;li&gt;track what features that is never been actually used.&lt;/li&gt;
  &lt;li&gt;what is a good cpu level for the application?&lt;/li&gt;
  &lt;li&gt;a way to track a call in all the services (as in a stack trace).&lt;/li&gt;
  &lt;li&gt;standardize the way that you monitor in your services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;8-security&quot;&gt;8. Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;authentication: I’m who I’m saying I am.&lt;/li&gt;
  &lt;li&gt;principal: who or what is been authenticated.&lt;/li&gt;
  &lt;li&gt;authorization: map the action that lets the principal execute it.&lt;/li&gt;
  &lt;li&gt;inside the own network, sometimes there is no authentication. But then is easier for an attack to get information once
inside this network.&lt;/li&gt;
  &lt;li&gt;use HTTPS&lt;/li&gt;
  &lt;li&gt;API keys allow a service to identify who is making a call, and place limits on what they can do.&lt;/li&gt;
  &lt;li&gt;application firewall can help throttle connections from certain IP ranges and detect other sorts of malicious attacks.&lt;/li&gt;
  &lt;li&gt;how do you revoke access to credentials when someone leaves the organization?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;9-other-notes-and-tools&quot;&gt;9. Other notes and tools&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;organizations that can change their structure is likely to have faster time to market.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;no matter how it looks at first, it’s always a people problem&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;assume that failure, in some aspect, is going to happen.&lt;/li&gt;
  &lt;li&gt;how long an operation can last? Can you expect a service to be down? How much data loss is acceptable?&lt;/li&gt;
  &lt;li&gt;what happens if “this” is down?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;fail fast!&lt;/strong&gt;. Do not have slow requests at your system. Avoid calling unhealthy systems in the first place.&lt;/li&gt;
  &lt;li&gt;use circuit breakers: all requests fails while the circuit breaker is in its blown state. After a certain period of time,
the client sends a few requests through to see if the service has recovered.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CQRS&lt;/strong&gt;: command-query responsibility segregation: the command and query parts of our system could live in different services,
or different hardware, and could make use of radically different types of data store.&lt;/li&gt;
  &lt;li&gt;be conscious about your cache configuration. Don’t let the cached data living too long.&lt;/li&gt;
  &lt;li&gt;you can autoscale when you see an increase in load or an instance failure.&lt;/li&gt;
  &lt;li&gt;use a service to share configuration between multiple nodes.&lt;/li&gt;
  &lt;li&gt;zookeeper: general or service specific configuration, allowing you to do tasks like dynamically changing log levels
or turning off features of a running system.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 03 Jan 2019 11:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2019-01-03-building-microservices</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2019-01-03-building-microservices</guid>
        
        
        <category>books</category>
        
        <category>architecture/design</category>
        
        <category>microservices</category>
        
      </item>
    
      <item>
        <title>Notes from Practical Vim</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://mrcosta.github.io/assets/images/books/practical_vim.jpg&quot; alt=&quot;drawing&quot; width=&quot;200&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some of the content of this book I already knew, but it was good to understand them in a deeper level and how can 
I extend the usage from most of the basic commands that I have been using before.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; command let us repeat the last change. It is the most powerful and versatile command vim&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;G&lt;/code&gt; command increases the indentation from the current line until the end of the file&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt; commands are all executed from Normal mode, but we also create a change each time we dip into
Insert mode. From the moment we enter in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IM&lt;/code&gt;, vim records every keystroke&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; to insert in the end of the current line&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; command will repeat the last search that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; command performed&lt;/li&gt;
  &lt;li&gt;to perform an substitution in a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:s/target/replacement&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; searchs for the next occurrence of the word under the cursor&lt;/li&gt;
  &lt;li&gt;vim records our keystrokes until we leave &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IM&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;the author mentions the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot formula&lt;/code&gt;: one keystroke to move, one keystroke to execute&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dw&lt;/code&gt; deletes a word&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dw&lt;/code&gt; deletes a word and a space&lt;/li&gt;
  &lt;li&gt;list of vim &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operators&lt;/code&gt;:
  they can operate on a single character &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl&lt;/code&gt;, a complete word &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;daw&lt;/code&gt;, or an entire paragraph &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dap&lt;/code&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;: change&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt;: delete&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt;: yank into register&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g~&lt;/code&gt;: swap case&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gu&lt;/code&gt;: make lowercase&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gU&lt;/code&gt;: make uppercase&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt;: shift right&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt;: shift left&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt;: autoindent&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;grammar: an action is composed from an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motion&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;when invoking the operator in duplication (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt; per example) it acts upon the current line&lt;/li&gt;
  &lt;li&gt;you can add operators to vim: take the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commentary.vim&lt;/code&gt; plugin. The operator it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gc&lt;/code&gt;, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; comments the current
line&lt;/li&gt;
  &lt;li&gt;editing from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IM&lt;/code&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + h&lt;/code&gt;: delete back one char&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w&lt;/code&gt;: delete back one word&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + u&lt;/code&gt;: delete back to start of the line&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;viw&lt;/code&gt;: select inner word in visual mode&lt;/li&gt;
  &lt;li&gt;to enter in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IM&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; it’s for before the current char and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; (append) after the current char&lt;/li&gt;
  &lt;li&gt;when we open a file, vim creates a new buffer and loads it into the current window&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;inline-search&quot;&gt;inline search&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f{char}&lt;/code&gt; searchs for the next char occurrence&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F{char}&lt;/code&gt; for previous char occurrence&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t{char}&lt;/code&gt; searchs for the char before next char occurrence&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T{char}&lt;/code&gt; searchs for the char before previous char occurrence&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; repeat the last character-search command&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; reverse the last character-search command&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;motions-for-lines&quot;&gt;motions for lines&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;j&lt;/code&gt;: down one real line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gj&lt;/code&gt;: down one display line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;k&lt;/code&gt;: up one real line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gk&lt;/code&gt;: up one display line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;: to first character of the real line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g0&lt;/code&gt;: to first character of the display line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ˆ&lt;/code&gt;: to first nonblank character of the real line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gˆ&lt;/code&gt;: to first nonblank character of the display line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt;: to end of the real line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g$&lt;/code&gt;: to end of the display line&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;motions-for-words&quot;&gt;motions for words&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;w&lt;/code&gt;: forward to start of next word&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;: backward to start of current/previous word&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt;: forward to end of current/next word&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ge&lt;/code&gt;: backward to end of previous word&lt;/li&gt;
  &lt;li&gt;append to end of word: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ea&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;append to end of previous word: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gea&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;definition of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WORD&lt;/code&gt;: sequence of nonblank characters separated with whitespaces&lt;/li&gt;
  &lt;li&gt;vim’s text objects consist of two characters, the first of which is always either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;. In general, we can say
that the text objects prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; select inside the delimiters, whereas those that are prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; select
everything including the delimiters&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ci&quot;&lt;/code&gt;: change inside the double quotes&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d{motion}&lt;/code&gt; tends to work well with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aw&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;as&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ap&lt;/code&gt; whereas the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c{motion}&lt;/code&gt; command works better with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iw&lt;/code&gt; and
similar&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;other-motions&quot;&gt;other motions&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt;: position before the last jump within current file&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt;: jumps between opening and closing sets of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(), {}, []&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Leader&amp;gt;f{char}&lt;/code&gt;: my leader key is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt;, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,f{char}&lt;/code&gt; would show the keys that I can press to go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{char}&lt;/code&gt;. This
also works with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AceJump&lt;/code&gt; IntelliJ plugin with you configure the keys properly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;surroundvim-plugin&quot;&gt;surround.vim plugin&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cs&quot;&apos;&lt;/code&gt;: change surround from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ds&apos;&lt;/code&gt;: delete surround &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ysiw[&lt;/code&gt;: add surround in an inner word with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;windows-management&quot;&gt;windows management&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + s&lt;/code&gt;: split current window horizontally&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + v&lt;/code&gt;: split current window vertically&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + w&lt;/code&gt;: cycle between open windows&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + h&lt;/code&gt;: focus the window to the left&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + j&lt;/code&gt;: focus the window below&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + k&lt;/code&gt;: focus the window above&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + l&lt;/code&gt;: focus the window right&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + c&lt;/code&gt;: close the active window&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + w + T&lt;/code&gt;: move the current window into its own tab&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{N}gt&lt;/code&gt;: switch to tab page number {N}&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt&lt;/code&gt;: switch to the next tab page&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gT&lt;/code&gt;: switch to the previous tab page&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;visual-mode&quot;&gt;visual mode&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt; enables character-wise visual mode&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;V&lt;/code&gt; enables line-wise visual mode&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl + v&lt;/code&gt; enables block-wise visual mode&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gv&lt;/code&gt; reselects the last visual selection&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; command in visual mode acts on the same amount of text as was marked by the most recent visual selection. But
doesn’t work so well sometimes&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vit&lt;/code&gt;: select the inner contents of a tag&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;copy-and-paste&quot;&gt;copy and paste&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;in Vim’s terminology, we don’t deal with the clipboard but instead with registers&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; command cuts the character under the cursor, placing a copy of it in the unnamed register after the cursor
position&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yyp&lt;/code&gt;: copy and paste line&lt;/li&gt;
  &lt;li&gt;“Oops! I clobbered my yank”: you had something to paste, but before pasting it you had to cut something and then your
previously yanked text was replaced by the cut that you did&lt;/li&gt;
  &lt;li&gt;vim’s delete command is equivalent to the standard cut operation&lt;/li&gt;
  &lt;li&gt;black hole register is addressed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; symbol, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_d{motion&lt;/code&gt; performs a true deletion&lt;/li&gt;
  &lt;li&gt;delete, yank and put commands interact with one of Vim’s registers. We can specify which register we want to use
by prefixing the command with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;{register}&lt;/code&gt;. If we don’t specify the register, then Vim will use the unnamed register&lt;/li&gt;
  &lt;li&gt;example: cut the current line into register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;bdd&lt;/code&gt; and paste it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;bp&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;when we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y{motion}&lt;/code&gt; command, the specified text is copied not only into the unnamed register but also into the
yank register, which is addressed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; symbol. The yank register is reliable, whereas the unnamed register is
volatile. We can cut something and when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;0p&lt;/code&gt; we would still have what we want&lt;/li&gt;
  &lt;li&gt;copying and paste from clipboard:
    &lt;ul&gt;
      &lt;li&gt;if we capture text in an external application, then we can paste it inside Vim using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;+p&lt;/code&gt; command&lt;/li&gt;
      &lt;li&gt;if we want to copy text from vim to an external application, then we have to use the register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;+&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;the visual selection in the document swaps places with the text in the register&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt;: pastes after the cursor position&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;P&lt;/code&gt;: pastes before the cursor position&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;macros&quot;&gt;macros&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;when recording a macro, ensure that every command is repeatable&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;w, b, e&lt;/code&gt; is better for macros than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h, j, k, l&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q{register}&lt;/code&gt; (you don’t need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt;) to start recording a macro. The word &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recording&lt;/code&gt; should appear in the status&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt; is a good register for a macro, so you just need to press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qq&lt;/code&gt; to start recording and then a final &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt; to finish&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{register}&lt;/code&gt; command executes the macro in the given register&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@@&lt;/code&gt; repeats the that was invoked most recently&lt;/li&gt;
  &lt;li&gt;to append commands in a macro: if you macro was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt;, then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q&lt;/code&gt;. Per example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qQ&lt;/code&gt; to start appending commands in the
previous macro that you recorded using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qq&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;search-and-replace&quot;&gt;search and replace&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s/going/rolling/g&lt;/code&gt;: it will search and replace in the whole file the word &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;going&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rolling&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s/going/rolling/gc&lt;/code&gt;: it will ask every time that it finds a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;going&lt;/code&gt; if we want to replace it for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rolling&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 27 Dec 2018 11:00:00 +0000</pubDate>
        <link>https://mrcosta.github.io/2018-12-27-practical-vim</link>
        <guid isPermaLink="true">https://mrcosta.github.io/2018-12-27-practical-vim</guid>
        
        
        <category>books</category>
        
        <category>editor</category>
        
        <category>vim</category>
        
      </item>
    
  </channel>
</rss>
