<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rafael Câmara</title>
    <description>The latest articles on DEV Community by Rafael Câmara (@rafaeljcamara).</description>
    <link>https://dev.to/rafaeljcamara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F783620%2F1d245875-bdd2-4d93-9bfc-0a391ca8160d.jpeg</url>
      <title>DEV Community: Rafael Câmara</title>
      <link>https://dev.to/rafaeljcamara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rafaeljcamara"/>
    <language>en</language>
    <item>
      <title>Ports and Adapters Architecture (Hexagonal Architecture) in practice with .NET</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Mon, 23 Jun 2025 12:56:53 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/ports-and-adapters-architecture-hexagonal-architecture-in-practice-with-net-1ibe</link>
      <guid>https://dev.to/rafaeljcamara/ports-and-adapters-architecture-hexagonal-architecture-in-practice-with-net-1ibe</guid>
      <description>&lt;p&gt;In one of my &lt;a href="https://dev.to/rafaeljcamara/ports-and-adapters-hexagonal-architecture-547c"&gt;previous blog posts&lt;/a&gt;, I wrote about the Ports and Adapters Architecture, also known as Hexagonal Architecture.&lt;/p&gt;

&lt;p&gt;Now we are going to apply those theoretical concepts in practice by using .NET.&lt;/p&gt;

&lt;p&gt;Before we go any further, here's an image to recap the structure of the Ports and Adapters Architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2cph1z9ro4fmgrfelvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2cph1z9ro4fmgrfelvr.png" alt="Hexagonal Architecture diagram" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The anatomy of a use case
&lt;/h2&gt;

&lt;p&gt;As mentioned in the aforementioned blog post, the Ports and Adapter Architecture is use case driven. Therefore, it's critical to clarify what a use case is and how to structure one properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a use-case
&lt;/h3&gt;

&lt;p&gt;Use cases are related to user intentions. They describe how users interact with your application to achieve a specific goal. As an example, a use case can be withdrawing money.&lt;/p&gt;

&lt;p&gt;In Hexagonal Architecture, use-cases encapsulate business logic, and you should avoid having a use-case call another use-case directly, as they represent different intentions in your system and should evolve independently and for different reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to structure a use-case
&lt;/h3&gt;

&lt;p&gt;First, it's important to clarify that Hexagonal Architecture is not prescriptive about how you should structure your code.&lt;/p&gt;

&lt;p&gt;So anything I mention here about code structure it's nothing but my own opinion on the subject.&lt;/p&gt;

&lt;p&gt;I like to think of use cases as actions that have an input and might return an output. Therefore, I like to use a variation of the &lt;a href="https://refactoring.guru/design-patterns/command" rel="noopener noreferrer"&gt;Command design pattern&lt;/a&gt; when it comes to the use cases.&lt;/p&gt;

&lt;p&gt;If you try to categorize use cases into groups, you will find 3 main ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;"Regular" use cases&lt;/strong&gt;&lt;/em&gt;. These are use cases that have an input and an output.&lt;/p&gt;

&lt;p&gt;Converting this to C#, it would look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IUseCase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TOutput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOutput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TInput&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;Unit use-cases&lt;/strong&gt;&lt;/em&gt;. The characteristic of these use cases is that they only have an input. Their return is void. You could use this use-case to execute some piece of logic where you don't care about any returns from it (what we could call a command in the CQRS world).&lt;/p&gt;

&lt;p&gt;Converting this to C#, it would look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IUnitUseCase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TInput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TInput&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;Nullary use-cases&lt;/strong&gt;&lt;/em&gt;. The characteristic of these use cases is that they only have an output. Their input is void. An example of where you might want to use this is when you want to get all the elements from a specific collection without any filters being applied (what we could call a query in the CQRS world).&lt;/p&gt;

&lt;p&gt;Converting this to C#, it would look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;INullaryUseCase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOutput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TOutput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically speaking, the ports we mentioned are inside the hexagon, so I will give no further explanation about them next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside the hexagon
&lt;/h2&gt;

&lt;p&gt;.NET wise, you can create a &lt;code&gt;Class Library&lt;/code&gt; project to hold this hexagon. Let's call it &lt;code&gt;Core&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwxay35i2jr7iyz2efna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwxay35i2jr7iyz2efna.png" alt="Location of the Core project in our Hexagonal solution" width="501" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned previously, inside the hexagon we will need to have our business logic. As suggested, this business logic can be encapsulated inside a use case.&lt;/p&gt;

&lt;p&gt;So, one of the things you can do is to create a port that maps this use case.&lt;/p&gt;

&lt;p&gt;Let's assume we want a port to compute a tax rate for a given continent.&lt;br&gt;
We can either directly use the &lt;code&gt;IUseCase&amp;lt;TInput, TOutput&amp;gt;&lt;/code&gt; interface or create a more specific one that inherits from this one, which is what we are going to do.&lt;/p&gt;

&lt;p&gt;This use case would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IComputeTaxRateUseCase&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IUseCase&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to make this use-case concrete. As an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ComputeTaxRateUseCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaxRate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INotification&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IComputeTaxRateUseCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;taxRateForContinent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSingleByAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taxRateForContinent&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NoTaxRateForContinentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;currentDayOfTheWeek&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DayOfWeek&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;updatedTaxRate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taxRateForContinent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;currentDayOfTheWeek&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotifyAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Tax Rate Computation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Computed tax rate for &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;updatedTaxRate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Timestamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;updatedTaxRate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this use case drives (i.e. uses) two other ports: one port for persistence (&lt;code&gt;IRepository&lt;/code&gt;) and another for notification (&lt;code&gt;INotification&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The interfaces for the driven ports are defined inside the hexagon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym8bzmyl9bwzaspwxx63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fym8bzmyl9bwzaspwxx63.png" alt="Ports location inside the Core project" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example port for &lt;code&gt;IRepository&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetSingleByAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementations are defined outside of it. We will have a look at them next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Driven Adapters (Right side of the hexagon)
&lt;/h2&gt;

&lt;p&gt;To host the driven adapters, I suggest creating a folder called &lt;code&gt;adapters&lt;/code&gt; and, inside it, create another folder that will host the driven adapters.&lt;/p&gt;

&lt;p&gt;In our case, we need to implement driven ports for two purposes: &lt;code&gt;ForPersistence&lt;/code&gt; and &lt;code&gt;ForNotification&lt;/code&gt;. We will create, again, a &lt;code&gt;Class Library&lt;/code&gt; for each one, and fake a &lt;code&gt;MongoDB&lt;/code&gt; and &lt;code&gt;RabbitMQ&lt;/code&gt; adapters (we will not provide exact implementations of them).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rb6v45sl9d60rh1yvcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rb6v45sl9d60rh1yvcf.png" alt="Adapters location" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As previously mentioned, the actual implementations of these adapters are simple and don't use the underlying technologies we mention.&lt;br&gt;
As an example, this is our fake &lt;code&gt;MongoDB&lt;/code&gt; implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MongoDbAdapter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MongoRepositoryAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//inject MongoDB context or client here&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetSingleByAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*** Mongo Adapter - Database query"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetCollectionOfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TaxRate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_collection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Europe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.20&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Africa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Asia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.18&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NorthAmerica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.22&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SouthAmerica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.19&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Oceania&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TaxRate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Antarctica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GetCollectionOfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaxRate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_collection&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"No collection found for type &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

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

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

&lt;/div&gt;



&lt;p&gt;As you can see, these adapters here have to implement the port specification that was specified inside the hexagon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Driver Adapters (Left side of the hexagon)
&lt;/h2&gt;

&lt;p&gt;Inside the &lt;code&gt;adapters&lt;/code&gt; folder create a folder called &lt;code&gt;driver&lt;/code&gt;. This folder will container all of our &lt;code&gt;driver&lt;/code&gt; adapters.&lt;/p&gt;

&lt;p&gt;Inside of it, we can create a &lt;code&gt;WebApi&lt;/code&gt; project that will host our &lt;code&gt;API&lt;/code&gt; adapter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnm2klgqguxasnre4dah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnm2klgqguxasnre4dah.png" alt="Driver adapters project location" width="505" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we will manage the endpoints that we are exposing to the outside world and adapt their language to the language that our use cases speak.&lt;/p&gt;

&lt;p&gt;For simplicity, we will create only one endpoint that will call our &lt;code&gt;IComputeTaxRateUseCase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This endpoint could look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/tax-rate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IComputeTaxRateUseCase&lt;/span&gt; &lt;span class="n"&gt;computeTaxRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cont&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Continent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;continent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;computeTaxRate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cont&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see here a bit of the adaptation I was previously speaking about. Our use case accepts an &lt;code&gt;Enum&lt;/code&gt; as input, but we get a &lt;code&gt;string&lt;/code&gt; from the outside world (from the actors). So our adapter does just that: adapts. It converts what we get from the actors to a language that our use-case understands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests as a driver/driven mechanism
&lt;/h2&gt;

&lt;p&gt;As you might have noticed in the previous screenshots, we had one folder called &lt;code&gt;test&lt;/code&gt; (even though there are no actual tests for simplicity's sake).&lt;/p&gt;

&lt;p&gt;Generally speaking, tests are important in software engineering, but they have a key role in hexagonal architecture as they have a highlighted role.&lt;/p&gt;

&lt;p&gt;Tests will provide with you an easy way to test how flexible your ports are, meaning if you can plug and play with anything. With tests, you can both simulate actions from the left and right side of the hexagon.&lt;/p&gt;

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

&lt;p&gt;Would you rather see this in video? Please check it &lt;a href="https://youtu.be/ld6epROxDcA" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In the video, I speak about other things, such as improving the isolation between projects even further with the &lt;code&gt;Composite Root&lt;/code&gt; design pattern.&lt;/p&gt;

&lt;p&gt;Check &lt;a href="https://github.com/RafaelJCamara/YT-Hexagonal.Architecture" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; for the source code.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Ports and Adapters (Hexagonal Architecture)</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Wed, 04 Jun 2025 19:27:21 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/ports-and-adapters-hexagonal-architecture-547c</link>
      <guid>https://dev.to/rafaeljcamara/ports-and-adapters-hexagonal-architecture-547c</guid>
      <description>&lt;p&gt;Have you ever wondered how you could isolate your application from external concerns, like which database to use? Or isolating it who is consuming your application?&lt;/p&gt;

&lt;p&gt;Domain-centric architectures, like the Ports and Adapters, allow you to achieve just that.&lt;/p&gt;

&lt;p&gt;The Ports and Adapters architecture, also known as Hexagonal architecture, was a concept started by Alistair Cockburn in 1994, but then officially &lt;a href="https://alistair.cockburn.us/hexagonal-architecture" rel="noopener noreferrer"&gt;written in his blog in 2005&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Its intention is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This connected to what we previously stated: isolating the business logic from everything external and that can be ever-changing.&lt;/p&gt;

&lt;p&gt;Our business logic is the money maker, so we must protect and isolate it from external dependencies. It should not be coupled to anything.&lt;/p&gt;

&lt;p&gt;The reason why you should care about this decoupling is because you should consider these external factors as ever-changing. These should be easily replaceable. You don't want to change your business logic just because your database type has changed, or because some application no longer is consuming your services via &lt;em&gt;HTTP&lt;/em&gt; and now uses &lt;em&gt;gRPC&lt;/em&gt;. You want your application to be tested, maintained, and evolve independently of such factors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the &lt;em&gt;Ports and Adapters&lt;/em&gt; architecture
&lt;/h2&gt;

&lt;p&gt;As stated previously, the Ports and Adapters architecture is an architectural style that aims at decoupling the business logic from external factors.&lt;/p&gt;

&lt;p&gt;It's a use-case-driven architecture, where you first think about the use cases, and then only about the implementation details like which database to use. By doing this, you could have your application running all in-memory, with in-memory dependencies, which is something that is very powerful when you think about it.&lt;/p&gt;

&lt;p&gt;Hexagonal architecture is not prescriptive on how you organize your code inside the hexagon. This makes applying this architectural style much easier, as the focus is on the isolation factor.&lt;/p&gt;

&lt;p&gt;Here's a visual overview of this pattern, before we proceed to explain each individual part:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpr3sulhz01x31yes96wk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpr3sulhz01x31yes96wk.png" alt="hexagonal architecture diagram, with primary and secondary drivers, ports and adapters" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's now address some of the most common terms associated with this pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;"The Hexagon"&lt;/strong&gt;&lt;/em&gt;: Before we go into details about what this is, first let us understand why the hexagon is the chosen shape. The reason is that, back in the day, every architecture diagram was using squares, and Alistair wanted a symmetrical shape that was not already taken and that could have room to insert ports and adapters freely.&lt;br&gt;
Now, as far as the purpose of the hexagon, this is where your core business logic is located, with your use cases and, possibly, domain constructs like domain entities, and so on. &lt;br&gt;
If you look at the architecture diagram above, you'll notice that everything that is on the left-hand side is called &lt;em&gt;&lt;strong&gt;Driver X&lt;/strong&gt;&lt;/em&gt;, where X is the element you are referring to (ex. driver adapter). The reason why it's called &lt;em&gt;Driver&lt;/em&gt; is because it's the element that is related to the usage of our application.&lt;br&gt;
The right-hand side is called &lt;em&gt;&lt;strong&gt;Driven X&lt;/strong&gt;&lt;/em&gt;. It's called this way because it's what the application uses.&lt;br&gt;
You must be wondering: &lt;em&gt;"Sure I have my business logic here, but how can I call it from the outside world? And how can I make use of databases or message brokers?"&lt;/em&gt;. This is where the concept of &lt;strong&gt;ports&lt;/strong&gt; comes in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Ports&lt;/strong&gt;&lt;/em&gt;: Ports are interfaces defined by the hexagon. Adapters outside the hexagon implement these interfaces (for driven ports) or consume them (for driving ports).&lt;br&gt;
We have two types of ports: the driver ports and the driven ports.&lt;br&gt;
In the case of the driver ports, they are used to call the use cases, for example, call a use case to debit from someone's bank account. &lt;br&gt;
The driven ports are used by our application to call the driven actors. For example, this port represents the contract that stores, retrieves, updates, and deletes objects from a database. &lt;br&gt;
You can organize the ports by their intent. For example, you can have a group of ports for notifications and another group of ports for administrative tasks.&lt;br&gt;
A misconception is that, because it's a hexagon, it means that we must have exactly 6 ports. This is something that is not correct. You can have as many ports as you want.&lt;br&gt;
So, now we have defined the contracts to interact with our application (and to access the outside world). Now comes the question: who uses such contracts? This is where the &lt;strong&gt;adapters&lt;/strong&gt; come into play.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Adapters&lt;/em&gt;&lt;/strong&gt;: These are the middle elements between the actors and the ports. The driver adapters must be coupled to a specific actor. For example, the driver adapter must be coupled to driver actors, so that they can convert the data they send into data that is compatible with the inputs of the use cases. On the other hand, the driven adapters must convert the data they get from the application to what the driven actor understands, and vice-versa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Driver actors&lt;/strong&gt;&lt;/em&gt;: Elements that are interested in using our application via our use cases. For example, a user in some Web portal performing administration tasks, or even a message broker is trying to push messages into our application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Driven actors&lt;/strong&gt;&lt;/em&gt;: Elements that our use cases use, like databases or message brokers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Enabling domain-centric architectures is always a safe bet when it comes to building resilient and adaptable software.&lt;/p&gt;

&lt;p&gt;Ports and adapters are just one way of contributing to this purpose.&lt;/p&gt;

&lt;p&gt;Want this see this in video? &lt;a href="https://youtu.be/DMS1EieXWMM" rel="noopener noreferrer"&gt;Check it out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Want to see this in practice? Stay tuned for the next posts!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Application Monitoring: Black-Box vs White-Box</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Sat, 24 May 2025 14:39:18 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/application-monitoring-black-box-vs-white-box-32ij</link>
      <guid>https://dev.to/rafaeljcamara/application-monitoring-black-box-vs-white-box-32ij</guid>
      <description>&lt;p&gt;Application monitoring, or just monitoring, refers to detecting if anything is failing in your application. Failures include performance degradation, capacity planning, security anomalies, and resource usage.&lt;/p&gt;

&lt;p&gt;These failures could have impacts, such as impacting directly your users, or 3rd parties that are reliant on you.&lt;/p&gt;

&lt;p&gt;So, with monitoring, we want to ensure that our system functions according to its expected behavior.&lt;/p&gt;

&lt;p&gt;In this spirit, there are two complementary ways that we can perform this monitoring: &lt;strong&gt;&lt;em&gt;Black-box&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;White-box&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Black-box monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With black-box monitoring, we look at the system you want to monitor from the perspective of the user or, broadly, putting yourself in the shoes of an external perspective.&lt;/p&gt;

&lt;p&gt;You don’t care about the internal implementation details, you are just interested in what are the observable outputs and behavior the system gives you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key characteristics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Focus on external behavior&lt;/strong&gt;&lt;/em&gt;: As stated previously, our intention is to monitor the system from the point of view of an external observer, like a user. So we want to look for things like how fast you can get a response, the availability of the services, and if the services are behaving as expected, meaning, that they deliver the promised set of features. This might include doing things a user would do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;No internal access&lt;/strong&gt;&lt;/em&gt;: Every conclusion is based on metrics and alerts that we take exclusively based on external observations, without any need to see the internal implementation details.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This black-box monitoring has the advantage of being user-centric, which means that it allows us to identify and fix any issues that might arise in the user journeys. Simplicity is also something that is a huge advantage of this approach since we don’t have to instrument or access any of the internal systems.&lt;/p&gt;

&lt;p&gt;Even though this black-box approach is simple, it might have some drawbacks. As mentioned earlier, one of the advantages of this approach is its simplicity due to the fact that we don’t have to be very granular with our instrumentation level. But this also can be a problem because it makes it harder to try to understand the root cause of something when things go out of normal.&lt;/p&gt;

&lt;p&gt;Another disadvantage of this approach is the fact that it alerts us whenever we have problems that are already impacting customers. This means that we are more reactive in our actions, and not as proactive as we should be.&lt;/p&gt;

&lt;p&gt;Now let’s have a look at this concept in practice. Assume that we are in the context of a streaming application. If you were taking this black-box approach, what you only care about is if the video you are loading on your screen is loading fast. You don’t care how the streaming service has implemented it, you just care that the video is being loaded fast.&lt;/p&gt;

&lt;p&gt;So, in summary, &lt;strong&gt;black-box monitoring is used to tell you something is wrong and might be impacting others&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;White-box monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this approach, you can now monitor your system in a transparent way. This means that you can directly instrument your code, or gather metrics from the infrastructure usage. You can be much more granular on what you can consider as the source for the monitoring data because you can see the inner workings of your system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key characteristics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;strong&gt;Focus on internal behavior&lt;/strong&gt;&lt;/em&gt;: In contrast with the black-box monitoring, here we are focused on the inner workings of the system. Collecting logs, metrics, and traces is our priority. The sources for such data can vary from infrastructure resources, like CPU and memory, to more application level, like the number of HTTP requests processed. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Developer-centric&lt;/strong&gt;&lt;/em&gt;: Often these metrics are used by developers, and the operations team, to understand the health and performance of the system.&lt;/p&gt;

&lt;p&gt;Even though this white-box approach is a bit more cumbersome, because the amount of things we might need to instrument is a bit higher than in the case of black-box monitoring, and generates a much bigger data volume, the white-box approach still has some advantages.&lt;/p&gt;

&lt;p&gt;First, let’s consider the fact that we are allowed to go deeper in our analysis. This goal is easier to achieve because we are much more granular when it comes to monitoring/observing.&lt;/p&gt;

&lt;p&gt;Secondly, based on the data that we can analyze, we can try to understand if there might exist problems for users. This means that approaches are more predictive than proactive.&lt;/p&gt;

&lt;p&gt;An example of using this approach is monitoring resources like CPU, and RAM, or even checking how performant your database queries are. Tracing is another example since it allows you to check the flow of a request inside your system.&lt;/p&gt;

&lt;p&gt;In summary, &lt;strong&gt;white-box monitoring is used to tell you why something is not ok and helps you to understand the root causes of such failures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which approach to use?&lt;/strong&gt;&lt;br&gt;
In my opinion, the discussion should not be about which one to use, but rather how we can create some symbiosis between the two.&lt;/p&gt;

&lt;p&gt;These two approaches should be seen as complimentary in the sense that, when used together, they give you a deeper understanding of the state and performance of your system.&lt;/p&gt;

&lt;p&gt;As stated previously, one gives us the notion that something is not going right, and the other one lets us dig deeper and understand why that’s happening.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>architecture</category>
      <category>monitoring</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>C# LINQ Any Explained</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Sat, 25 Jan 2025 22:05:08 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/c-linq-any-explained-3d58</link>
      <guid>https://dev.to/rafaeljcamara/c-linq-any-explained-3d58</guid>
      <description>&lt;p&gt;The &lt;code&gt;Any&lt;/code&gt; LINQ method allows you to check if there are elements in a given collection that satisfy a given condition. If &lt;strong&gt;&lt;em&gt;at least one element&lt;/em&gt;&lt;/strong&gt; satisfies the condition, &lt;code&gt;true&lt;/code&gt; is returned. Otherwise, &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you provide no condition to check against the collection's elements, the &lt;code&gt;Any&lt;/code&gt; LINQ method will check if the collection has any elements. If elements are present in the collection, the method will return true. Otherwise, false.&lt;/p&gt;

&lt;p&gt;Let's assume we have the following list of numbers: &lt;code&gt;[1, 2, 3, 4, 5]&lt;/code&gt;, and you want to check if there are numbers that are greater than &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this case, we do have &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysb5h1mqahav7f3d2xug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysb5h1mqahav7f3d2xug.png" alt="list that contains numbers 1, 2, 3, 4, and 5 and highlights 4 and 5" width="800" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we have &lt;strong&gt;&lt;em&gt;at least one element&lt;/em&gt;&lt;/strong&gt; that satisfies the condition, the &lt;code&gt;Any&lt;/code&gt; method will return &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we change the condition to check if any elements are greater than &lt;code&gt;10&lt;/code&gt;, the outcome would be &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Any in code
&lt;/h2&gt;

&lt;p&gt;Let's first start by creating our sample collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;SimpleCollection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test the first scenario, which checks if any elements are greater than &lt;code&gt;3&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isBiggerThan3&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the condition &lt;code&gt;number =&amp;gt; number &amp;gt; 3&lt;/code&gt;. It's passed as a lambda expression to the &lt;code&gt;Any&lt;/code&gt; method and will be tested against the elements of the collection.&lt;/p&gt;

&lt;p&gt;The variable &lt;code&gt;isBiggerThan3&lt;/code&gt; would hold the value of &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the second scenario, we would have to adjust our code to something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isBiggerThan10&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;isBiggerThan10&lt;/code&gt; would hold the value of &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you are more of a visual learner, I’ve created a &lt;a href="https://www.youtube.com/playlist?list=PLE49pLzZX0zJBG8dSKMI7A2F-R5Z039Gh" rel="noopener noreferrer"&gt;playlist&lt;/a&gt; showcasing the &lt;code&gt;Any&lt;/code&gt; LINQ method and other ones.&lt;/p&gt;

&lt;p&gt;If you want to go directly to the &lt;code&gt;Any&lt;/code&gt; videos, here are the direct links for the &lt;a href="https://www.youtube.com/watch?v=NBogZ9gBSvA&amp;amp;list=PLE49pLzZX0zJBG8dSKMI7A2F-R5Z039Gh&amp;amp;index=4" rel="noopener noreferrer"&gt;theory&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=hSUob74unfw&amp;amp;list=PLE49pLzZX0zJBG8dSKMI7A2F-R5Z039Gh&amp;amp;index=5" rel="noopener noreferrer"&gt;practice&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/RafaelJCamara/LINQ-Course/blob/main/LinqCourse/LinqCourse/CollectionEvaluators/Any.cs" rel="noopener noreferrer"&gt;Here&lt;/a&gt; you can find a variation of the source code presented in this article.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>tutorial</category>
      <category>coding</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Downstream Resiliency: The Timeout, Retry, and Circuit-Breaker Patterns</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Mon, 02 Dec 2024 14:23:17 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/downstream-resiliency-the-timeout-retry-and-circuit-breaker-patterns-2bej</link>
      <guid>https://dev.to/rafaeljcamara/downstream-resiliency-the-timeout-retry-and-circuit-breaker-patterns-2bej</guid>
      <description>&lt;p&gt;As systems become more connected and dependent, downstream resiliency has become a key consideration in service architecture, guiding how an application responds in case dependent services fail.&lt;/p&gt;

&lt;p&gt;This article will dive into downstream resiliency and how timeouts, retries, and circuit breakers work together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Downstream Resiliency?
&lt;/h2&gt;

&lt;p&gt;Downstream Resiliency refers to the capability of a service, say Service A, to function properly when there are failures contributed by its downstream dependencies, for instance, Service B, which itself may further rely on another service (Service C). Most of the time, especially in distributed architectures like microservices, services do not operate in isolation. For example, Service A might call Service B, and that in turn calls Service C to complete its requests. When these services experience either latency or outage, it is important for the originating service, Service A in this case, to implement various measures to handle such situations gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeouts
&lt;/h2&gt;

&lt;p&gt;The first line of defense for ensuring downstream resiliency is the implementation of timeouts. A timeout is a period after which a service will stop waiting for a response from a downstream call. Imagine Service A calling Service B and waiting indefinitely for a response. This can lead to resource exhaustion as Service A holds onto resources while it waits for a response. With a set timeout, Service A can free up resources and resume its functioning even if Service B takes longer to respond.&lt;/p&gt;

&lt;p&gt;However, determining the optimal timeout duration is critical. Too short of a timeout could lead to unnecessary failures, and respective potential retries, while too long could waste valuable resources. Utilizing observability tools can help in understanding the typical response times and setting an appropriate timeout threshold, usually slightly higher than the average response time observed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries
&lt;/h2&gt;

&lt;p&gt;Retries occur when an initial request to a downstream service fails or times out. The assumption in such scenarios is that the failure might be transient, meaning that the service is very much capable of handling requests but is just temporarily overwhelmed. In such a case, by retrying the request, Service A can probably receive a successful response without overwhelming Service B.&lt;/p&gt;

&lt;p&gt;When it comes to retries, one of the most important characteristics is to understand which backoff strategy we should adopt. A backoff strategy just refers to how long we should wait between retries.&lt;br&gt;
There are a couple of strategies we can go with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constant Interval&lt;/strong&gt;: Retrying after a fixed duration. For example retry every second.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxerjgejp3oej0xw4v1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxerjgejp3oej0xw4v1f.png" alt="Constant retry" width="541" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linear Interval&lt;/strong&gt;: In this, the wait time is increased linearly after each retry. As an example, the first retry happens after 1 second, the second retry after 2 seconds, and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2puh8jf3nronct6w2vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2puh8jf3nronct6w2vn.png" alt="Linear interval" width="551" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exponential Interval&lt;/strong&gt;: The wait time increases exponentially, thereby helping to reduce the load on Service B. Normally the base of the exponent is 2. For example, the first retry happens at 2 seconds (2 to the power of 1 [retry attempt]), the second at 4 seconds (2 to the power of 2 [retry attempt]), the third at 8 seconds (2 to the power of 3 [retry attempt]), and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymxqtua9jt4flifvi16z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymxqtua9jt4flifvi16z.png" alt="Exponential interval" width="532" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exponential Backoff with Jitter&lt;/strong&gt;: Introduce randomness in the retry intervals to avoid a "thundering herd" problem where all services retry at the same time and overwhelm Service B. It's the same as the exponential interval but with an added random jitter. For example, the first retry happens at 2.2 seconds (2 to the power of 1 [retry attempt] plus random 0.2 seconds of jitter), the second at 4.7 seconds (2 to the power of 2 [retry attempt] plus random 0.7 seconds of jitter), and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhstqlubxt7hcda7merw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhstqlubxt7hcda7merw9.png" alt="Exponential Interval with Jitter" width="536" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Circuit-Breaker
&lt;/h2&gt;

&lt;p&gt;While retries are suitable for transient issues between services, circuit breakers handle scenarios where a service is likely down, i.e. non-transient failures. The circuit breaker pattern changes the state of the service based on the success or failure of a number of requests. It has three states: &lt;strong&gt;Closed&lt;/strong&gt;, &lt;strong&gt;Open&lt;/strong&gt;, and &lt;strong&gt;Half-Open&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's a high-level overview of the states and their respective transitions:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29gsp3425iawmdt49qnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29gsp3425iawmdt49qnx.png" alt="High-level circuit breaker" width="652" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;Closed&lt;/strong&gt; state, requests flow normally.&lt;/li&gt;
&lt;li&gt;If a threshold of failures is reached, the circuit breaker transitions into the &lt;strong&gt;Open&lt;/strong&gt; state, blocking all requests to that service for a defined timeout period.&lt;/li&gt;
&lt;li&gt;It transitions after this time into the &lt;strong&gt;Half-Open&lt;/strong&gt; state, when a request is made, to test whether the downstream service has recovered. If the request is successful, it transitions back into the &lt;strong&gt;Closed&lt;/strong&gt; state; if not, into the &lt;strong&gt;Open&lt;/strong&gt; state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a more visual explanation of these state changes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(1)&lt;/em&gt; &lt;strong&gt;Closed circuit&lt;/strong&gt;. Everything is flowing normally and ok between services:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa58o5fcy8070ojr6babo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa58o5fcy8070ojr6babo.png" alt="closed state" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(2)&lt;/em&gt; &lt;strong&gt;Open circuit&lt;/strong&gt;. After a specific number of requests fail (you configure this number/threshold), the downstream dependency is considered as faulty, therefore the circuit is opened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfttojixsmo45a8v2ajv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfttojixsmo45a8v2ajv.png" alt="open circuit" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(3)&lt;/em&gt; After a period of the time of open circuit (which is also configured by you), we allow the next request to flow through, to test the waters. By doing so, the first step is to move the state of the circuit to half-opened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91wqu73uwvx32bte9t6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91wqu73uwvx32bte9t6h.png" alt="hal-open circuit" width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The system won't stay here. The next state will depend on the success of the response to this request. If positive the system will go back to the closed state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kvvidqxdwxhucrdxmkb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kvvidqxdwxhucrdxmkb.png" alt="closed state after half-open" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Otherwise, it goes to the open state.&lt;/p&gt;

&lt;p&gt;These state changes will continue for as long as the system is alive.&lt;/p&gt;

&lt;p&gt;This process prevents Service A from constantly trying to reach a non-responsive Service B, thus saving resources and generally contributing to system stability.&lt;/p&gt;

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

&lt;p&gt;In summary, downstream resilience is a must-have to ensure the stability of modern applications dependent on several services. Adding timeouts, using retry strategies, and applying circuit-breakers build a resilient system that can handle failures in downstream dependencies gracefully. Each of these has its own subtlety and requires careful consideration and monitoring to ensure they work as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you are more of a visual learner, I’ve created &lt;a href="https://www.youtube.com/watch?v=vTAO0Yz-RSA" rel="noopener noreferrer"&gt;a video&lt;/a&gt; to showcase the concepts explained here.&lt;/p&gt;

</description>
      <category>development</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Automate Your C# Library Deployment: Publishing to NuGet and GitHub Packages with GitHub Actions</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Mon, 04 Nov 2024 22:46:46 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/automate-your-c-library-deployment-publishing-to-nuget-and-github-packages-with-github-actions-2707</link>
      <guid>https://dev.to/rafaeljcamara/automate-your-c-library-deployment-publishing-to-nuget-and-github-packages-with-github-actions-2707</guid>
      <description>&lt;p&gt;So you’ve created a cool C# library that you want to share with your fellow developers, but don’t know how? Maybe you know you could do that with NuGet packages, but don’t know how to create one?&lt;/p&gt;

&lt;p&gt;This post showcases how you can make this amazing library you’ve created publicly available so that others can enjoy working with it!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a NuGet package?
&lt;/h2&gt;

&lt;p&gt;A NuGet package is a single, packaged library or set of libraries, complemented by metadata and dependencies, designed to easily be distributed and integrated into projects in &lt;em&gt;.NET&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This saves time for the developers by avoiding rewriting or duplicating code, as we promote reusability by installing these packages and making use of their functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample library code
&lt;/h2&gt;

&lt;p&gt;We are going to be a very simple logger class that just prints a message to the console. This printing will evolve to showcase that new changes in our library code can be automatically deployed to the package feeds, but we will come to this in a second.&lt;/p&gt;

&lt;p&gt;First, let’s create a class library project. We can do so via de command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new classlib -n Something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The outcome should look something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusgc2fw6hh5zh2nxzhgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusgc2fw6hh5zh2nxzhgi.png" alt="base class lib" width="442" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now change the directory to our project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd MyAmazingLogger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another thing we can do is to remove the default Class1.cs file.&lt;/p&gt;

&lt;p&gt;Then, let’s create a class that represents the functionality we want to share. In this case, a logger class. Here’s some sample code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomLogger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogMyMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"v1: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have this base code class let’s make this shareable across the world :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the continuous integration (ci) workflow file
&lt;/h2&gt;

&lt;p&gt;If you want your GitHub actions to trigger whenever an event occurs, as an example a commit is made in main.&lt;/p&gt;

&lt;p&gt;To configure our GitHub actions we need to place the yaml files inside a specific folder structure: &lt;code&gt;.github&lt;/code&gt; → &lt;code&gt;workflows&lt;/code&gt; → &lt;code&gt;ci.yaml&lt;/code&gt; (this can be named anything)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnssqut2i9y9tjqij3441.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnssqut2i9y9tjqij3441.png" alt="github action folder structure" width="318" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;ci.yaml&lt;/code&gt; file contains the code that will package our library and publish it to the corresponding package source. This file can do many more things, like building the app, running tests, generating docker images, and so on, we are just using a very small fraction of the abilities this gives us.&lt;/p&gt;

&lt;p&gt;Now let’s see how this file can look depending on the target package source. For each one of them, I’ll first introduce the final version of the &lt;code&gt;ci.yaml&lt;/code&gt; file and then explain the file in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing to GitHub Packages with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Here’s the CI manifest file to publish your NuGet packages to GitHub packages, via Github actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generate-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GitHub Tag Bump&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tab_bump&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anothrNick/github-tag-action@1.71.0&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;INITIAL_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
          &lt;span class="na"&gt;DEFAULT_BUMP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;patch&lt;/span&gt;

    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;new_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.tab_bump.outputs.new_tag }}&lt;/span&gt;

  &lt;span class="na"&gt;package-and-publish-lib&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;generate-version&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup .NET&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-dotnet@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8.0.x&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate NuGet package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;dotnet pack MyAmazingLogger/ \&lt;/span&gt;
          &lt;span class="s"&gt;--configuration Release \&lt;/span&gt;
          &lt;span class="s"&gt;-p:PackageVersion=${{ needs.generate-version.outputs.new_version }} \&lt;/span&gt;
          &lt;span class="s"&gt;-p:RepositoryUrl=https://github.com/RafaelJCamara/YT-Nuget-Pkg-Release \&lt;/span&gt;
          &lt;span class="s"&gt;-o packages&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish NuGet package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet nuget push packages/*.nupkg --api-key ${{ secrets.PUSH_NUGET }} --source https://nuget.pkg.github.com/RafaelJCamara/index.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s analyze the important bits.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to trigger a package publish
&lt;/h3&gt;

&lt;p&gt;Based on what we have in our manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packages are going to be published whenever we have some code merged to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What steps are involved
&lt;/h3&gt;

&lt;p&gt;We know that our packages need to have a version. This version follows a format called &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;&lt;code&gt;semantic versioning&lt;/code&gt;&lt;/a&gt;. This is where the job called &lt;code&gt;generate-version&lt;/code&gt; comes in. The output of this job is a version number that will be used when we publish our package in the &lt;code&gt;package-and-publish-lib&lt;/code&gt; job.&lt;/p&gt;

&lt;p&gt;So, as we can see, we have two main high-level overview steps: one to generate a package version and another to use that generated version in the package to be published.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing the &lt;code&gt;generate-version&lt;/code&gt; job
&lt;/h2&gt;

&lt;p&gt;This job only has one step and that step’s only responsibility is to generate a package version.&lt;/p&gt;

&lt;p&gt;To help us on this task we are using an action called &lt;a href="https://github.com/anothrNick/github-tag-action" rel="noopener noreferrer"&gt;&lt;code&gt;anothrNick/github-tag-action&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you can see from our manifest file, we have the following environment variables necessary for this action to properly work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GITHUB_TOKEN&lt;/code&gt;: This token is required for permissioning the tag in the repo. We can use a built-in token called &lt;code&gt;secrets.GITHUB_TOKEN&lt;/code&gt;, you don’t have to configure anything to access this token. This token is automatically generated for your repo by GitHub and allows you to safely interact with GitHub’s Apis and your repository, allowing you to do things like publishing packages. As of the writing of this post, this token only has read permissions, therefore we can’t write anything. This is why we have this section at the top of the &lt;code&gt;generate-version&lt;/code&gt; job:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give our token enough permission to write the tags.&lt;/p&gt;

&lt;p&gt;If you don’t give write permissions, this is the error you will get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsn2dqsf42jipbroxijyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsn2dqsf42jipbroxijyy.png" alt="error when you don't have write permissions" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s another way to solve this problem which is to not use that GitHub token and create your own token with read and write permissions. We will see how we can do this when we speak about the token usage for publishing packages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;INITIAL_VERSION&lt;/code&gt;: This presents an initial version we might have. Keep in mind that the notation followed is the semantic versioning one and that the first run of this will increment upon this default value. As an example, if the default value is &lt;em&gt;1.0.0&lt;/em&gt; with &lt;em&gt;default_bump&lt;/em&gt; &lt;strong&gt;patch&lt;/strong&gt; and we run our GitHub action, the end value will be &lt;em&gt;1.0.1&lt;/em&gt;, and not &lt;em&gt;1.0.0&lt;/em&gt; on the first run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DEFAULT_BUMP&lt;/code&gt;: This represents how the increments will happen. The value we are using is &lt;code&gt;patch&lt;/code&gt;, meaning that it will have increments like this: 1.0.&lt;strong&gt;5&lt;/strong&gt; to 1.0.&lt;strong&gt;6&lt;/strong&gt;. We can have other bump strategies, choose one that best fits your use case.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information on these configurations, and possibly others you can enable, please take a look at the &lt;a href="https://github.com/anothrNick/github-tag-action?tab=readme-ov-file#options" rel="noopener noreferrer"&gt;action’s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you may have noticed, we have defined an output from the job. This is useful so that we can use the produced tag number in other jobs, which is what we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;new_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.tab_bump.outputs.new_tag }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see from the snippet, we are defining an output with key &lt;code&gt;new_version&lt;/code&gt;, which is pretty much just returning the value from the &lt;code&gt;GitHub Tag Bump&lt;/code&gt; step. Just note that we had to give an ID to the step (&lt;code&gt;tab_bump&lt;/code&gt;) so that we could target the step’s output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing the &lt;code&gt;package-and-publish-lib&lt;/code&gt; job
&lt;/h2&gt;

&lt;p&gt;The two main responsibilities of this job are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Package our code into a NuGet package (*.nupkg)&lt;/li&gt;
&lt;li&gt;Publish this package into a package feed (in this case GitHub packages)&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Choosing the appropriate .NET version (step Setup .NET)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generating the NuGet package (step Generate NuGet package)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publishing this NuGet package (step Publish NuGet package)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s analyze each step with care.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Choosing the appropriate .NET version (step &lt;code&gt;Setup .NET&lt;/code&gt;)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;This step simply uses the action &lt;code&gt;actions/setup-dotnet@v1&lt;/code&gt; to set up our .NET version (in this case .NET 8).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Generating the NuGet package (step &lt;code&gt;Generate NuGet package&lt;/code&gt;)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s bring the package command closer to us so that we can analyze it better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; dotnet pack MyAmazingLogger/ &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;--configuration&lt;/span&gt; Release &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-p&lt;/span&gt;:PackageVersion&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ needs.generate-version.outputs.new_version &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-p&lt;/span&gt;:RepositoryUrl&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/RafaelJCamara/YT-Nuget-Pkg-Release &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-o&lt;/span&gt; packages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to understand that we use the dotnet pack command to generate our NuGet package. In our case, we are using a couple of flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--configuration Release&lt;/code&gt;: we want to use the Release configuration because it’s more performant and tends to generate bundles with lower storage requirements (smaller size bundles).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-p:PackageVersion=${{ needs.generate-version.outputs.new_version }}&lt;/code&gt;: here we are specifying the NuGet package version. As you remember, we generated this version on the previous job (&lt;code&gt;generate-version&lt;/code&gt;) and we need to access this output. To do so we can use the &lt;code&gt;needs&lt;/code&gt; keyword, then specify the job we want to get the output from (&lt;code&gt;generate-version&lt;/code&gt;), and then access the &lt;code&gt;outputs&lt;/code&gt; property of this job and then the key of our output (which we named &lt;code&gt;new_version&lt;/code&gt;). When you do this, you can get the generated version!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-p:RepositoryUrl=https://github.com/RafaelJCamara/YT-Nuget-Pkg-Release&lt;/code&gt;: What this is doing is adding the repository URL metadata to the published NuGet package. There is another way of doing this, which we will cover shortly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-o packages&lt;/code&gt;: Specifies the directory where the generated NuGet package should be placed. In this case, the output will be stored in the &lt;code&gt;packages&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this step, we have our NuGet package ready to be published!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Publishing this NuGet package (step &lt;code&gt;Publish NuGet package&lt;/code&gt;)&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Let’s take a closer look at the publish command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet nuget push packages/&lt;span class="k"&gt;*&lt;/span&gt;.nupkg &lt;span class="nt"&gt;--api-key&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.PUSH_NUGET &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--source&lt;/span&gt; https://nuget.pkg.github.com/RafaelJCamara/index.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To publish our package we need to use the &lt;code&gt;dotnet nuget push&lt;/code&gt; command. We need to provide 3 important values to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Where the NuGet package is located&lt;/code&gt;. We do so by passing the &lt;code&gt;packages/*.nupkg&lt;/code&gt; parameter. This would normally match with what you’ve inserted as the output of your dotnet pack command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where the package feed/repository is located. In this case, our source is &lt;code&gt;https://nuget.pkg.github.com/RafaelJCamara/index.json&lt;/code&gt;. Since we are using the GitHub package repository we have a special source structure: &lt;code&gt;https://nuget.pkg.github.com/{github-username}/index.json&lt;/code&gt;. This means that if your username is LostJohn1234 your source would be something like &lt;code&gt;https://nuget.pkg.github.com/LostJohn1234/index.json&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;api-key&lt;/code&gt; to access the feed. As you can see, we are passing a token from the GitHub secrets. This means we need to create one token that has permission to write packages. In the next section, I’ll show you how to do it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating a GitHub secret
&lt;/h3&gt;

&lt;p&gt;Let’s see how we can create a secret token that has permission to write NuGet packages to our GitHub package feed.&lt;/p&gt;

&lt;p&gt;First, let’s go to your profile &lt;code&gt;Settings&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;Go to the &lt;code&gt;Developer Settings&lt;/code&gt; section, and select &lt;code&gt;Tokens (classic)&lt;/code&gt; inside the &lt;code&gt;Personal access tokens&lt;/code&gt;. Generate a classic token.&lt;/p&gt;

&lt;p&gt;Make sure you have something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8h972d8l68eiug2vzk46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8h972d8l68eiug2vzk46.png" alt="github token with write permissions" width="782" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you generate the token, make sure you copy it because now we must add that token as a secret for our repository.&lt;/p&gt;

&lt;p&gt;In your repository, click &lt;code&gt;Settings&lt;/code&gt;. Inside the Security section, there is a subsection called &lt;code&gt;Secrets and variables&lt;/code&gt; and under that there’s &lt;code&gt;Actions&lt;/code&gt;. Make sure to click &lt;code&gt;Actions&lt;/code&gt;. On Actions, create a &lt;code&gt;new repository secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Name&lt;/code&gt; field, you need to put the secret name that matches what we have in the manifest file. This secret name was called &lt;code&gt;PUSH_NUGET&lt;/code&gt;, but you can call it whatever you want with the condition that it must match what you wrote in the manifest.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Secret&lt;/code&gt; field, you must place the token value you got from the previous step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing to NuGet Feed with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Here’s the CI manifest file to publish your NuGet packages to the NuGet feed, via Github actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generate-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GitHub Tag Bump&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tab_bump&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anothrNick/github-tag-action@1.71.0&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;INITIAL_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
          &lt;span class="na"&gt;DEFAULT_BUMP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;patch&lt;/span&gt;

    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;new_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.tab_bump.outputs.new_tag }}&lt;/span&gt;

  &lt;span class="na"&gt;package-and-publish-lib&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;generate-version&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup .NET&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-dotnet@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8.0.x&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate NuGet package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;dotnet pack MyAmazingLogger/ \&lt;/span&gt;
          &lt;span class="s"&gt;--configuration Release \&lt;/span&gt;
          &lt;span class="s"&gt;-p:PackageVersion=${{ needs.generate-version.outputs.new_version }} \&lt;/span&gt;
          &lt;span class="s"&gt;-p:RepositoryUrl=https://github.com/RafaelJCamara/YT-Nuget-Pkg-Release \&lt;/span&gt;
          &lt;span class="s"&gt;-o packages&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish NuGet package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet nuget push packages/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between this manifest file and the previous one for GitHub packages is only two: the &lt;code&gt;--source&lt;/code&gt; flag in the &lt;code&gt;Publish NuGet package&lt;/code&gt; step and an adjustment we need to make in the &lt;code&gt;api-key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before the source was the feed that was bound to your GitHub profile, but now the source needs to be the source of the NuGet feed: &lt;code&gt;https://api.nuget.org/v3/index.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As far as the &lt;code&gt;api-key&lt;/code&gt;, before our api-key was a secret that had a token that belonged to your GitHub profile, but now we must generate a token in &lt;a href="https://www.nuget.org/" rel="noopener noreferrer"&gt;&lt;code&gt;nuget.org&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every other step remains the same as before, so I advise you to take a read of what was written before and make the adjustments we are making in the section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a NuGet api-key
&lt;/h3&gt;

&lt;p&gt;First of all, head out to &lt;a href="https://www.nuget.org/" rel="noopener noreferrer"&gt;&lt;code&gt;nuget.org&lt;/code&gt;&lt;/a&gt; and do your registration.&lt;/p&gt;

&lt;p&gt;After doing so successfully, click on your profile name and select the &lt;code&gt;API Keys&lt;/code&gt; section. Click &lt;code&gt;Create&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Select an expiration date that serves your interests and also make sure to put the correct scopes (you would need to add permission to push new packages and versions). You might also need to add the &lt;code&gt;*&lt;/code&gt; attribute in the &lt;code&gt;Global Pattern&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;Make sure you have something like this in the end:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft07o2bny8g0hayx7xyuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft07o2bny8g0hayx7xyuf.png" alt="nuget.org package token" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your key should be now visible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6svdh59yb1woyyd7cxtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6svdh59yb1woyyd7cxtl.png" alt="final nuget.org token" width="596" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to click &lt;code&gt;Copy&lt;/code&gt; and take this value and put it as the &lt;code&gt;Secret&lt;/code&gt; value in our &lt;code&gt;PUSH_NUGET&lt;/code&gt; repository secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready. Set. Action.
&lt;/h2&gt;

&lt;p&gt;After all of this setup, let's commit our code. When you do, by default, it’s going to do so in the &lt;code&gt;main&lt;/code&gt; branch, which means that our workflow will trigger.&lt;/p&gt;

&lt;p&gt;Now the outcome actually depends on which package source you are using.&lt;/p&gt;

&lt;p&gt;If you are using &lt;em&gt;GitHub’s Package repository&lt;/em&gt;, you should see your package on the right-hand side of your repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88ijwendolahcx3akjp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88ijwendolahcx3akjp2.png" alt="github repository with published packages" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will also notice that next to your commit you will have a success icon (or fail icon) if the underlying GitHub Action went fine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscqg2jy9pwgabi6guw9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscqg2jy9pwgabi6guw9k.png" alt="commit message with failed icon for failed GitHub action" width="686" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If, on the other hand, you have used the nuget.org feed, this is what you should see in your published packages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymbvepif5z69z3mbawcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymbvepif5z69z3mbawcp.png" alt="published NuGet package in nuget.org" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, you should be able to see the package you have published, with the correct version number attached to it.&lt;/p&gt;

&lt;p&gt;Regardless of how many changes you now do on your package, all of these changes will now be automatically published to your chosen package feed!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use your custom NuGet packages
&lt;/h2&gt;

&lt;p&gt;This step depends on which package repository you’ve used.&lt;/p&gt;

&lt;p&gt;If you have used the default NuGet feed, you don’t need to do anything special to use your newly created package. Just go ahead and install it! It’s a plug-and-play because this feed comes by default with .NET. To check the current feeds you have, run the command &lt;code&gt;dotnet nuget list source&lt;/code&gt;. If you haven’t added any feed, this is the outcome you should have:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy0wbmhws9l3fpymhgh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy0wbmhws9l3fpymhgh5.png" alt="my current NuGet sources locally" width="364" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have published your NuGet package to GitHub’s package repository, we must add it to our current list of sources. To do that we must run this command: &lt;code&gt;dotnet nuget add source &amp;lt;your GitHub package feed&amp;gt; --name MyGitHubNuGetFeed&lt;/code&gt;. Normally the &lt;code&gt;&amp;lt;your GitHub package feed&amp;gt;&lt;/code&gt; has a structure like &lt;code&gt;https://nuget.pkg.github.com/{your GitHub username}/index.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case, the &lt;code&gt;&amp;lt;your GitHub package feed&amp;gt;&lt;/code&gt; would be &lt;code&gt;https://nuget.pkg.github.com/RafaelJCamara/index.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After adding your GitHub package feed, we can run the list source command again and see the newly added feed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcygvptkfuvhcudwle4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcygvptkfuvhcudwle4f.png" alt="new sources" width="477" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can install your package freely!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding metadata to the published NuGet package
&lt;/h2&gt;

&lt;p&gt;As I stated previously, we can set metadata related to our NuGet package in another way, and that another way is by adding metadata in the library &lt;code&gt;.csproj&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Each property specifies information that will be included in the package manifest, allowing others to understand the purpose, licensing, and source of the package when they download it from &lt;code&gt;nuget.org&lt;/code&gt; or other sources. Here’s a breakdown of each property:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;PackageId&amp;gt;&lt;/code&gt;: This is the unique identifier for your NuGet package (in this case, &lt;code&gt;MyAmazingLogger&lt;/code&gt;). It’s what users will search for when they want to install your package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;Version&amp;gt;&lt;/code&gt;: Defines the version of your package, following semantic versioning (e.g., &lt;code&gt;1.0.0&lt;/code&gt;). This version appears in NuGet package listings and helps users identify updates or specific versions to install. Currently, we are not going to use this, due to our version being created in the GitHub Action.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;Authors&amp;gt;&lt;/code&gt;: Specifies the package author(s). This can be a single name or a list of contributors and helps users know who created and maintains the package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;PackageDescription&amp;gt;&lt;/code&gt;: Provides a short description of your package. This text is displayed on &lt;code&gt;nuget.org&lt;/code&gt;, where users can see what your package does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;PackageLicenseExpression&amp;gt;&lt;/code&gt;: Indicates the license type for your package, such as &lt;code&gt;MIT&lt;/code&gt;, &lt;code&gt;Apache-2.0&lt;/code&gt;, or &lt;code&gt;GPL&lt;/code&gt;. NuGet uses this to show the licensing terms, which is important for clarity regarding the legal usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;PackageTags&amp;gt;&lt;/code&gt;: These tags help improve discoverability on NuGet. For example, tagging it as &lt;code&gt;Loggers&lt;/code&gt;, it makes it easier for users to find your package when they search for logging-related functionality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;RepositoryUrl&amp;gt;&lt;/code&gt;: This is the URL for the repository where the package source is hosted, often on GitHub. This allows users to view the source code, file issues, or contribute to the project.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you package and publish the project to NuGet, these metadata values are included in the &lt;code&gt;.nuspec&lt;/code&gt; file (the package manifest) and displayed on the package’s page on &lt;code&gt;nuget.org&lt;/code&gt;. Don’t worry if some of this information does not showcase if you publish your package in the GitHub package repository, from my experience it tends to not show some of the metadata. Regardless, it’s interesting and important to have such metadata.&lt;/p&gt;

&lt;p&gt;Here’s an example of how your metadata can look like in nuget.org:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgl3f9tgs03hjttt8j90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgl3f9tgs03hjttt8j90.png" alt="example metadata in NuGet package" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Here’s the &lt;a href="https://github.com/RafaelJCamara/YT-Nuget-Pkg-Release" rel="noopener noreferrer"&gt;&lt;code&gt;source code&lt;/code&gt;&lt;/a&gt; for this post.&lt;/p&gt;

&lt;p&gt;If you are more of a visual learner, I’ve created a &lt;a href="https://www.youtube.com/watch?v=dQ_L4aIRbMM&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;video&lt;/a&gt; to showcase the tutorial explained here.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>githubactions</category>
      <category>nuget</category>
    </item>
    <item>
      <title>C4 Model - The Basics</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Sun, 27 Oct 2024 08:57:06 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/c4-model-the-basics-5bk5</link>
      <guid>https://dev.to/rafaeljcamara/c4-model-the-basics-5bk5</guid>
      <description>&lt;p&gt;Software Architecture is all about developing systems that scale and are maintainable. Clear visualizations will help teams to communicate the design effectively. The &lt;a href="https://c4model.com/" rel="noopener noreferrer"&gt;C4 model&lt;/a&gt; comes in handy for this task! But what is C4, and why should you care?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is the C4 model?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The C4 model is a framework that enables the documentation and visualization of software architecture. It gives a structured means of creating diagrams showing how different software systems interact with each other. While some people are quite satisfied with other solutions such as UML or general-purpose tools like draw.io or Excalidraw, C4 can come across as simpler and more standardized, while keeping your diagrams from bloating and being over-engineered.&lt;/p&gt;

&lt;p&gt;While there are no fixed rules on how to build your software architecture diagrams, C4 attempts to bring clarity and standardization into this process. It is versatile enough to cover a wide range of detail levels, from high-level overviews to more technical and in-depth diagrams.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Use C4?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The value of C4 is in its simplicity and flexibility. You can have very basic diagrams that give someone a general sense of your system architecture but then go into more detailed diagrams, such as deployment models.&lt;/p&gt;

&lt;p&gt;If you opt-out by using the diagram-as-code path, you can easily have this source controlled, which means that you see our architecture growing and evolving as time goes by.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4 Levels of the C4 Model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The C4 Model explains the architecture of a system from four levels of abstraction: &lt;strong&gt;&lt;em&gt;context&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;container&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;component&lt;/em&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;em&gt;code&lt;/em&gt;&lt;/strong&gt;. Each of them depicts the same system architecture in greater detail than the previous one. &lt;/p&gt;

&lt;p&gt;Let's dive into each level and what it tries to tell.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Context Diagram&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Context Diagram provides a very high-level overview of the software system and its relationship to external dependencies. This diagram is about showing where your software would sit within the larger landscape, and it will highlight the external systems it interfaces with, such as external APIs, databases, or third-party services like Stripe or an e-mail service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: High-level understanding of how the system interacts with the outside world. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: Both technical and nontechnical stakeholders. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Details&lt;/strong&gt;: Would a non-technical person get it instantly from this diagram? If not try to further simplify it.&lt;/p&gt;

&lt;p&gt;Here’s an example of a context diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxabpz0iriyucn68haz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxabpz0iriyucn68haz0.png" alt="context diagram" width="399" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Container Diagram&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Container Diagram zooms in one level further from the overall system into the different containers making up your system. Containers are essentially executables: for example, backend services, front-end applications, or databases. This level helps tear down how various containers are interconnected, showing what their individual responsibilities will be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Understand the building blocks of your system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: More technical stakeholders who require further details than what the Context Diagram can give them. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Details&lt;/strong&gt;: More often than not, in this layer, one could introduce more technical information, like the programming languages being used and the types of databases. Where the Context Diagram usually tries to convey the whole, big picture, the Container Diagram goes into the internal structure of the system.&lt;/p&gt;

&lt;p&gt;Here’s an example of a container diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0kpyu3cdfe7s0q6xwnz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0kpyu3cdfe7s0q6xwnz.png" alt="component diagram" width="540" height="1063"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Component Diagram&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Component Diagram goes even further, as it zooms into the details inside of each container and the internal components that make it up. For instance, if one container is a web application, this diagram can go down to controllers, services, or even repositories inside an application and how they might talk with one another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Breaking down each container to show how internal components work together. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: Technical teams for closer views of the inner details. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Details&lt;/strong&gt;: The level of detail is higher here; hence, it is best used for teams that are directly working on the software.&lt;/p&gt;

&lt;p&gt;Here’s an example of a component diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wf3f59q4zjt1ooeeb4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wf3f59q4zjt1ooeeb4r.png" alt="container diagram" width="504" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Code Diagram&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In that case, the Code Diagram focuses primarily on the internal structure that components usually contain, classes, or objects. Not every situation demands this amount of detail, and such diagrams are frequently created automatically by tools, such as Integrated Development Environments (IDEs). Since C4 doesn't define the notations at this level, other modeling notations, such as UML, can be used to represent code structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: The implementation level details will be depicted, such as class structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: All the developers that need to see code-level details. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Details&lt;/strong&gt;: Often this level can be generated automatically with tools, hence it might not be necessary to create these diagrams manually. &lt;/p&gt;

&lt;p&gt;Here’s an example of a code diagram, taken from the C4 docs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0na019rcggkbklm9az95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0na019rcggkbklm9az95.png" alt="code diagram" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://c4model.com/diagrams" rel="noopener noreferrer"&gt;https://c4model.com/diagrams&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When to Use Different Levels of C4&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Another strength of the C4 Model is that it's so flexible, meaning you don't have to use all four levels all of the time. For many systems, drawing a Context Diagram and a Container Diagram will often be sufficient to communicate what a team needs to know about the system. You can often convey the largest part of the information for most stakeholders using just these two levels.&lt;/p&gt;

&lt;p&gt;If you're working on a very complex system, or if you need to document more about the system, then that's the time to introduce Component and Code Diagrams. Remember, the deeper the level of detail you want, like using a Code Diagram, the more things change and the more you have to adjust this diagram, and this is an added cost on its own in terms of maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Architecture vs. Design&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Where Does C4 Fit? This interesting debate discusses whether a very detailed diagram, like a Code Diagram, must be taken into consideration in software architecture, or if it is more about software design. &lt;/p&gt;

&lt;p&gt;Architecture is basically concerned with higher-level decisions on the structure and the behavior of the system, while design in general covers the implementation of the single components.&lt;/p&gt;

&lt;p&gt;This debate emphasizes the flexibility of the C4 Model—whether you use it strictly for architectural purposes or extend it into design is totally up to your team's needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pros and Cons of Using the C4 Model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As with any approach, there are strengths and weaknesses associated with using the C4 Model. Here's a quick rundown:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Pros&lt;/em&gt;&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standardized Approach&lt;/strong&gt;: The C4 provides a lucid, consistent means to visualize the architecture, which can be quite helpful while onboarding new members into a team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible&lt;/strong&gt;: You can choose how much detail to include, from high-level architecture to low-level code structures. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Communication&lt;/strong&gt;: Non-technical stakeholders can understand the high-level diagrams, thus enhancing communication across teams. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Cons&lt;/em&gt;&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;: The learning curve may be involved in getting started if your team is not comfortable with the C4 Model. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;: Detailed diagrams-such as the Code or Component diagrams-may require frequent updates because the system is always evolving, hence adding to more maintenance work. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The C4 Model is a very useful tool for clear and structured visualization of software architecture. Whether it is for high-level overviews when starting or deep insights into the system's internal structure, C4 supports documenting architecture in a way that is understandable and maintainable.&lt;/p&gt;

&lt;p&gt;With a small learning curve, the payoffs of using C4 far outweigh the initial setup effort. This is a great investment to maintain clarity and healthy software systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you are more of a visual learner, I’ve created two YouTube videos to cover C4, &lt;a href="https://www.youtube.com/watch?v=uspC06QgUxw&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;one&lt;/a&gt; more focused on theory and &lt;a href="https://www.youtube.com/watch?v=mtzplEH337I&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;another&lt;/a&gt; focused on practice.&lt;/p&gt;

&lt;p&gt;You can find the first 3 diagrams &lt;a href="https://github.com/RafaelJCamara/Youtube-C4-Model" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also check these amazing resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://c4model.com/" rel="noopener noreferrer"&gt;https://c4model.com/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/plantuml-stdlib/C4-PlantUML" rel="noopener noreferrer"&gt;https://github.com/plantuml-stdlib/C4-PlantUML&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Introducing wontbreak</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Fri, 03 May 2024 16:47:44 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/introducing-nebula-http-resiliency-3ghp</link>
      <guid>https://dev.to/rafaeljcamara/introducing-nebula-http-resiliency-3ghp</guid>
      <description>&lt;p&gt;Hello everyone!&lt;/p&gt;

&lt;p&gt;I'm very happy to announce my second open-source project called wontbreak. You can find its source code on &lt;a href="https://github.com/Nebula-Software-Systems/wontbreak" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is my first npm package, which aims to make your axios requests more resilient.&lt;/p&gt;

&lt;p&gt;It implements 3 common resiliency patterns: timeout, retry, and circuit-breaker.&lt;/p&gt;

&lt;p&gt;Please refer to the README in the project for a more in-depth analysis and usage of this project!&lt;/p&gt;

&lt;p&gt;As always, please feel free to provide some feedback!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>axios</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Latency vs Throughput</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Wed, 21 Sep 2022 20:36:53 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/latency-vs-throughput-1e29</link>
      <guid>https://dev.to/rafaeljcamara/latency-vs-throughput-1e29</guid>
      <description>&lt;p&gt;In today's blog we are going to discuss the difference between latency and throughput. These are two important metrics when analysing the performance of our systems.&lt;/p&gt;

&lt;p&gt;So let's just get right into it!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Latency&lt;/em&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As a fancy definition of latency, we can say that latency is the amount of time it takes data to traverse from one part of your system to another. &lt;br&gt;
When we think about latency, we think of a client-server architecture, and this specific latency is the amount of time it takes for a client to get a response from the server.&lt;/p&gt;

&lt;p&gt;But there are other ways of latency. For example, reading a piece of data from memory or from disk.&lt;/p&gt;

&lt;p&gt;In an ideal scenario, you would want to minimize the latency of your system, because this might make a big difference on the client side. The lower the client has to wait for his request, the happier it is.&lt;/p&gt;

&lt;p&gt;There might be some tuning needed in order to make our latency lower. For instance, use networks with high speeds, make use of mechanisms such as cache or reading from memory (instead of disks), have geographically distributed systems (for example, when a game has a server in Europe and another in America).&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Throughput&lt;/em&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Throughput is the &lt;strong&gt;amount of work a machine can do in a given period of time&lt;/strong&gt;. An example of this would be the amount of requests a server can handle in a second.&lt;/p&gt;

&lt;p&gt;In an ideal scenario, we would want our system to serve as many requests as possible, meaning high throughput. If you run a business, the more clients you can serve, the higher the revenue you will get from it is.&lt;/p&gt;

&lt;p&gt;Stuff you can do to make your system's throughput higher include have one super powerful server or have multiple servers to handle the requests. This is quite a debate on whether to use one powerful server or have multiple servers, but if your system serves a lot of traffic, chances are you're better off by having multiple decent servers.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Notes&lt;/em&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;There one important aspect we must have in consideration. We can’t conclude anything about latency/throughput, by taking in consideration the other one. Let me give you a couple of examples to clarify this.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;u&gt;First scenario:&lt;/u&gt;&lt;/em&gt; does low latency means high throughput?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The answer is &lt;strong&gt;no&lt;/strong&gt;. For example, our server may be a really slow one (low throughput), but it is not serving requests at the moment. This means that my request will be served immediately by the server, thus resulting in low latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;u&gt;Second scenario&lt;/u&gt;&lt;/em&gt;: does low throughput means high latency?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Again, the answer is &lt;strong&gt;no&lt;/strong&gt;. This example is tied to the one above. Just because our server is slow (low throughput), doesn't mean we will necessarily have high latency. Our server can handle a couple of requests and be really fast in serving them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;😁 &lt;strong&gt;I hope this has helped!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's everything for now! Thank you so much for reading.&lt;/p&gt;

&lt;p&gt;If you have any questions please feel free to drop them off. &lt;br&gt;
Follow me if you want to read more about these kinds of topics!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Social Media Links&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/rafaelcamara96/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/RafaJCamara" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RafaelJCamara" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>systems</category>
    </item>
    <item>
      <title>C# "using" keyword</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Thu, 05 May 2022 21:48:49 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/c-using-keyword-1fih</link>
      <guid>https://dev.to/rafaeljcamara/c-using-keyword-1fih</guid>
      <description>&lt;p&gt;In today's tutorial, we are going to discuss one of the keywords we frequently need to use: the &lt;em&gt;using&lt;/em&gt; keyword!&lt;/p&gt;

&lt;p&gt;Let's get straight to it!&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;using&lt;/em&gt;&lt;/strong&gt; keyword can be used in two contexts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;As namespace directive&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;using&lt;/em&gt; statement blocks&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Namespace directive
&lt;/h2&gt;

&lt;p&gt;There are three ways in which we can use &lt;em&gt;using&lt;/em&gt; here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make use of namespaces (traditional usage)&lt;/li&gt;
&lt;li&gt;Make aliases for namespaces&lt;/li&gt;
&lt;li&gt;Use static methods from classes namespaces&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Down below I will explain each one of them, with a simple example involving writing a message to the console.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1. Make use of namespaces (traditional usage)
&lt;/h3&gt;

&lt;p&gt;As we know, to write a message to the console we must use our friend &lt;em&gt;Console.WriteLine&lt;/em&gt;.&lt;br&gt;
We have two ways of calling &lt;em&gt;Console.WriteLine&lt;/em&gt;. The first one is by calling the fully qualified name, which in this case would be &lt;em&gt;System.Console.WriteLine&lt;/em&gt;. The second one would be using the &lt;em&gt;using&lt;/em&gt; keyword. The problem with the first approach is that, whenever we want to &lt;em&gt;Console.WriteLine&lt;/em&gt;, we must prepend with &lt;em&gt;System&lt;/em&gt;. Doing this once is fine, but imagine having to do so multiple times. Even further, imagine if we had a bigger namespace, say &lt;em&gt;Amazing.Big.Complex.DomainNamespace&lt;/em&gt;, which would be needed to call every time we wanted to call a method. This would degrade very much the readability of our code.&lt;/p&gt;

&lt;p&gt;In the following figure, you can see an example of this using statement, as well as the other "not so good" use case mentioned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f86s2qmaqwdpg5f1jzl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f86s2qmaqwdpg5f1jzl.png" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1.2. Make aliases for namespaces
&lt;/h3&gt;

&lt;p&gt;Creating aliases for namespaces, at a visual glance, seems like creating a variable. In order to better explain this concept, please refer to the below image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F688llhmqk4yx46rjlz63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F688llhmqk4yx46rjlz63.png" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the first line, we create kinda a variable to store an alias for a specific namespace. In this case, it would not be worth it to make it, but with a bigger codebase, it could make sense in order to organize and make things look easier to read. Beware that this is not a widely used practice!&lt;/p&gt;

&lt;p&gt;After declaring the alias we use it in the method &lt;em&gt;WriteMessageToConsoleWithAlias&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  1.3. Use static methods from classes namespaces
&lt;/h3&gt;

&lt;p&gt;In this example, the WriteLine method is a static method from a static class (&lt;em&gt;Console&lt;/em&gt; class). Every time we want to execute the &lt;em&gt;WriteLine&lt;/em&gt; method, we must call &lt;em&gt;Console&lt;/em&gt; first. We can improve that by using the static class in the namespace. The following figure shows how to do so.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jhasdmeolhe921hllr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jhasdmeolhe921hllr1.png" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the first line, we have inserted the &lt;em&gt;static&lt;/em&gt; keyword and also added the &lt;em&gt;Console&lt;/em&gt; class to the namespace. This will allow us to use the static methods inside the &lt;em&gt;Console&lt;/em&gt; class in our code without always needing to write &lt;em&gt;Console.WriteLine&lt;/em&gt;. You can see this inside the &lt;em&gt;WriteMessageToConsoleWithStaticMethod&lt;/em&gt;, where we call the &lt;em&gt;WriteLine&lt;/em&gt; method without needing to prepend the &lt;em&gt;Console&lt;/em&gt; class.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. &lt;em&gt;using&lt;/em&gt; statement blocks
&lt;/h2&gt;

&lt;p&gt;The using block statements are used when we want to create and manage object resources in a specific scope. When the scope ends, those resources are freed. Using the using block is important because there are types of objects that the Garbage Collector cannot clear, so we need to release such objects explicitly. Examples of such objects are file streams or database connections. Please refer to &lt;a href="https://www.codingame.com/playgrounds/6179/garbage-collection-and-c" rel="noopener noreferrer"&gt;this&lt;/a&gt; article for more information on this topic.&lt;/p&gt;

&lt;p&gt;If that might seem confusing, let's have a look at this simple, but clarifying, coding example, which writes a specific content to a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void WriteToFile(string fileName, string content){
     using (StreamWriter writer = new StreamWriter(filename))
     {
          writer.WriteLine(content);
     } //after this, resources used are freed
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important aspect to notice here is that the objects we use in the parenthesis of the &lt;em&gt;using&lt;/em&gt; statement must implement the IDisposible interface. This interface contains the &lt;em&gt;Dispose&lt;/em&gt; method that will be called whenever the scope of the &lt;em&gt;using&lt;/em&gt; block ends. This &lt;em&gt;Dispose&lt;/em&gt; method objective should be cleaning the object mentioned before.&lt;/p&gt;

&lt;p&gt;If we don't do what we mentioned before, and simply wrote two WriteLine methods from two StreamWriter, we would get an error (similar to the one you see in the figure down below).&lt;br&gt;
That error occurs because the resources (from which &lt;em&gt;file1.txt&lt;/em&gt; is one of them) that are used are not freed up like they are when we use them inside the using block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy92y2w5vy6rpzmsng7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy92y2w5vy6rpzmsng7t.png" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if, instead, you use the &lt;em&gt;using&lt;/em&gt; blocks, you don't have this error, due to the freeing of the resources. The following image shows just that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffye9cb18m8s9wxz1ka51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffye9cb18m8s9wxz1ka51.png" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😁 &lt;strong&gt;I hope this has helped!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's everything for now! Thank you so much for reading.&lt;/p&gt;

&lt;p&gt;The source code for this tutorial can be found &lt;a href="https://github.com/RafaelJCamara/CSharpUsingKeyword" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions please feel free to drop them off. &lt;br&gt;
Follow me if you want to read more about these kinds of topics!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Social Media Links&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/rafaelcamara96/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/RafaJCamara" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RafaelJCamara" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>C# extension methods</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Tue, 26 Apr 2022 20:32:58 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/c-extension-methods-159k</link>
      <guid>https://dev.to/rafaeljcamara/c-extension-methods-159k</guid>
      <description>&lt;p&gt;In this tutorial, we will discuss how to use extensions methods in C# and the aspects to be aware of when doing so.&lt;/p&gt;

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;Extensions methods are methods that we can add to our code or third-party library, that allows to extend or add functionality.&lt;/p&gt;

&lt;p&gt;When to use them or not is something that we will address later on, but for now, let's see a simple coding example to show this concept in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coding example
&lt;/h3&gt;

&lt;p&gt;Let's assume we are handed a third-party library whose only purpose is to log messages (in our case to the console). For simplicity's sake, the log class is written down below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    /*
     * Let's assume this is given in a third party library
     */
    public class Logger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message: {message}");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 4&lt;/strong&gt;: Declaration of the Logger class.&lt;br&gt;
&lt;strong&gt;Line 6 to 8&lt;/strong&gt;: Log method, that logs the message passed as argument.&lt;/p&gt;

&lt;p&gt;If we needed to log a particular message, we just needed to instantiate the Logger class and call the log method.&lt;/p&gt;

&lt;p&gt;So far so good.&lt;/p&gt;

&lt;p&gt;But what if we wanted to give "special" treatment to error messages and print something like "An error occurred. This was the error: {INSERT_ERROR_MESSAGE}"? We don't have access to that source code, so we can't change the Logger library.&lt;/p&gt;

&lt;p&gt;C# provides us a way of extending the functionality of the Logger library without modifying the original source code. Add the following code to the previous one shown for the library. The result of adding this would be having an extra method (the LogError method).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public static class LoggerExtensions
    {
        public static void LogError(this Logger logger, string errorType, string message)
        {
            Console.WriteLine($"Error {errorType}: {message}");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's analyze what we just did.&lt;br&gt;
&lt;strong&gt;Line 1&lt;/strong&gt;: Created a static class that will contain all the extensions we can create for the Logger library.&lt;br&gt;
&lt;strong&gt;Line 3 to 6&lt;/strong&gt;: Created a static method, which represents the additional method we are adding to the library, that logs the error type and an error message.&lt;br&gt;
Here we have a couple of things to notice:&lt;br&gt;
     - The first parameter has to be the class to be extended. To do so, we must first use the keyword this and then insert the class to be extended like a traditional parameter.&lt;br&gt;
     - After the first parameter, we must add the remaining wanted parameters, like a "regular" method. As we can see from the method, two parameters have been added: errorType and message.&lt;/p&gt;

&lt;p&gt;The following image shows the log obtained.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb7l31gg1f8d6hzc3704.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftb7l31gg1f8d6hzc3704.png" alt="Log obtained by executing the Log method inside the Logger Class" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, we extended the functionality of a particular class, but we can also abstract this even more and consider extending functionality to interfaces. This means that every class that implements that interface will also be able to use the extended method.&lt;/p&gt;

&lt;p&gt;Let's have a look at this in practice, with our Logger class.&lt;br&gt;
Have in consideration the following code to be added and modified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public interface ILogger
    {
        void Log(string message);
    }

public static class LoggerExtensions
    {
        public static void LogError(this ILogger logger, string errorType, string message)
        {
            Console.WriteLine($"Error {errorType}: {message}");
        }
    }

    /*
     * Let's assume this is given in a third party library
     */

    public class Logger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message: {message}");
        }
    }

    public class AnotherLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine($"Logged message in another logger: {message}");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changes that were inserted:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt;: Creation of the ILogger interface, containing the important log method.&lt;br&gt;
&lt;strong&gt;Line 3&lt;/strong&gt;: Log method to be implemented.&lt;br&gt;
&lt;strong&gt;Line 5&lt;/strong&gt;: Extension class that will contain our extension methods.&lt;br&gt;
&lt;strong&gt;Line 7 to 10&lt;/strong&gt;: Extension method created. As we can see from the method's signature, everything that implements the ILogger interface will have this method available.&lt;br&gt;
&lt;strong&gt;Line 16&lt;/strong&gt;: Created a Logger class that implements the aforementioned interface.&lt;br&gt;
&lt;strong&gt;Line 24&lt;/strong&gt;: Create another Logger class. The purpose of this is to check that every class that implements that interface will have the extension method created available.&lt;/p&gt;

&lt;p&gt;Notice the static class we created for extensions and compare it with the same class from the previous example. Notice the difference? In our first example, we were extending the Logger class, but now we extended the interface ILogger, and the impact of this is that, as mentioned before, every class that implements the interface will access the extension method.&lt;/p&gt;

&lt;p&gt;If we now instantiate Logger and AnotherLogger objects, we can see that the extension method is available to us.&lt;/p&gt;

&lt;p&gt;The following image shows precisely a possible execution output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foamf7oe7iuixht2g8hob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foamf7oe7iuixht2g8hob.png" alt="Log obtained by executing the Log method inside the Logger Class and the AnotherLogger Class" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One last final piece of information to have in consideration is that you can also have extension methods in enums. The rationale behind it is the same as with interface, so we won't go into much detail (also because it's not as common to do extension methods in enums).&lt;/p&gt;

&lt;p&gt;Before moving on, if you want to take a look at the source code, you can find it &lt;a href="https://github.com/RafaelJCamara/CSharpExtensionMethodsTutorial" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;😁 &lt;strong&gt;I hope this has helped!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's everything for now! Thank you so much for reading.&lt;/p&gt;

&lt;p&gt;If you have any questions please feel free to drop them off. &lt;br&gt;
Follow me if you want to read more about these kinds of topics!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Social Media Links&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/rafaelcamara96/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/RafaJCamara" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RafaelJCamara" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>SOLID principles explained</title>
      <dc:creator>Rafael Câmara</dc:creator>
      <pubDate>Wed, 09 Mar 2022 22:14:07 +0000</pubDate>
      <link>https://dev.to/rafaeljcamara/solid-principles-explained-14en</link>
      <guid>https://dev.to/rafaeljcamara/solid-principles-explained-14en</guid>
      <description>&lt;p&gt;The SOLID principles are a set of good practices of the Object-Oriented Design (OOD) world. We should have them in consideration when producing our software if we want it to be more easily scalable, maintainable, and extended.&lt;/p&gt;

&lt;p&gt;SOLID is an acronym, and each character of this acronym refers to an OOD principle, explained down below.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;S&lt;/em&gt;&lt;/strong&gt; - Single Responsibility Principle&lt;/p&gt;

&lt;p&gt;One class should have only one responsibility. Sometimes you can see this principle written as "One class should only have one reason to change". All of this means that a class should only do one job, and do it right!&lt;/p&gt;

&lt;p&gt;Let's take a look at a small coding example.&lt;/p&gt;

&lt;p&gt;Say we have a class responsible for managing our users, whose code can be seen below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class User {
    private String name;
    private int age;

    public User(int name, int age){
        this.name = name;
        this.age = age;
    }

    public void saveUserToDatabase(){
        //implementation detail
    }

    //getters and setters
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from the above code, besides having the basic getters and setters, this class is also responsible for saving the user in the database.&lt;/p&gt;

&lt;p&gt;The previous class, being a data container, should only change if changes in our data model occur. With our current class that doesn't happen, because we have a second reason to change. Every time we want to change the database logic, we will have to change our class, and that breaks the Single Responsibility Principle.&lt;/p&gt;

&lt;p&gt;The code below shows an example of the refactor we needed to do to have obedience to this principle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class User {
    private String name;
    private int age;
    private InfoPersistenseProvider database;

    public User(int name, int age, InfoPersistenseProvider database){
        this.name = name;
        this.age = age;
        this.database = database;
    }

    public void saveUserToDatabase(){
        this.database.saveToDatabase();
    }

    //getters and setters
    ...
}

public class InfoPersistenseProvider{

    public InfoPersistenseProvider(){}

    public void saveToDatabase(User user){
        //implementation detail
    }

    //getters and setters
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from the previous code example, what we did was remove the database logic to a separated class. &lt;br&gt;
Let's resume the example of changing the database type logic. Instead of changing the User class code, we only change the class that holds such logic, which in our case is the InfoPersistenseProvider class. If tomorrow we wanted to change such logic as well, we would only change in the proper place, which would always comply with the Single Responsibility Principle.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;O&lt;/em&gt;&lt;/strong&gt; - Open/Closed Principle&lt;/p&gt;

&lt;p&gt;A class should be open for extension but closed for modifications. This means that we can add new functionalities without changing the existing code of the "base" class (that was extended).&lt;/p&gt;

&lt;p&gt;Now let's take a look at a small coding example below, where we compute the user's interest in a specific video content, based on its previous consumption habits, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Video{
    private String type;

    //...

    public double computeUserInterest(){
        if(this.type.equals("Movie")){
            //compute movie interest
        }else if(this.type.equals("TVShow")){
            //compute TVShow interest
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens if you want to add 10 new video types to our platform? Our if-else would become gigantic. This example, where we constantly add if blocks, represents a classic example of the violation of the Open/Closed principle.&lt;/p&gt;

&lt;p&gt;How can we obey to this principle?&lt;br&gt;
In the code block below we show how.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface Video{
    public double computeUserInterest();
}

public class Movie implements Video{
    public double computeUserInterest(){
        //implementation detail
    }
}

public class TVShow implements Video{
    public double computeUserInterest(){
        //implementation detail
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Now, what happens if you want to add a new video type to our platform? You just need to make the class implement our interface. This makes our code cleaner and, more important, obeying to the Open/Close principle.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;L&lt;/em&gt;&lt;/strong&gt; - Liskov Substitution Principle&lt;/p&gt;

&lt;p&gt;In practical terms, this principle states that if you have a parent class and one of its subclasses, you can replace the parent class by the subclass and still have valid behavior. This is the basic behavior we find in the OOP principle &lt;strong&gt;inheritance&lt;/strong&gt;, meaning the subclass should be able to do everything its parent class does.&lt;/p&gt;

&lt;p&gt;Let's analyze the upcoming block of code to understand this concept better!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Movie{
    public void play(){
        //implementation detail
    }

    public void increaseVolume(){
        //implementation detail
    }
}

public class Joker extends Movie{

}

public class ASilentMovie extends Movie{
    @Override
    public void increaseVolume(){}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's say we have our Movie superclass, which has two main actions: play (which starts the movie) and increaseVolume (which increases the movie's volume). This logic will work in most of the movies produced in today's day and age, but there is a market niche for silent movies which, as we all know, do not have any volume. &lt;/p&gt;

&lt;p&gt;Do we have a correct behavior if, all of sudden, in our code we replaced a Movie object with another object that represents a silent movie? The answer is NO. No, because of the increaseVolume action. It is not correct to say "I will increase the volume of a silent movie", because there is no such thing as the concept of volume in these kinds of movies! This means that we don't obey the Liskov Substitution Principle.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;I&lt;/em&gt;&lt;/strong&gt; - Interface Segregation Principle&lt;/p&gt;

&lt;p&gt;According to this principle, a class should not be forced to implement methods that it does not depend upon. A nice rule of thumb here is if you detect that you are making a dummy/empty implementation of a method (like the increaseVolume in the ASilentMovie class in the previous example), you are breaking this principle. The purpose here is to have our classes have only the methods that they need to perform their jobs.&lt;/p&gt;

&lt;p&gt;Let's continue with our previous movie example, but a bit refactored, to see this principle in action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface Movie{
    public void play();
    public void increaseVolume();
}

public class Joker implements Movie{
    public void play(){
        //implementation detail
    }

    public void increaseVolume(){
        //implementation detail
    }
}

public class ASilentMovie implements Movie{
    public void play(){
        //implementation detail
    }

    public void increaseVolume(){
        //implementation detail [PROBLEM HERE]
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we saw from the previous Movie example, there was a problem when we tried to increase the volume of a silent film. We were breaking the Liskov Substitution Principle. As you can now see, and as previously mentioned, we are also breaking the Interface Segregation principle, because the ASilentMovie class is depending(implementing) on a method that is not used.&lt;/p&gt;

&lt;p&gt;We can refactor this to comply with the Interface Segregation Principle, as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface MoviePlayManager{
    public void play();
}

public interface AudioManager{
    public void increaseVolume();
}

public class Joker implements MoviePlayManager,AudioManager{
    public void play(){
        //implementation detail
    }

    public void increaseVolume(){
        //implementation detail
    }
}

public class ASilentMovie implements MoviePlayManager{
    public void play(){
        //implementation detail
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, our ASilentMovie class only depends on the methods it actually uses!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;D&lt;/em&gt;&lt;/strong&gt; - Dependency Inversion Principle&lt;/p&gt;

&lt;p&gt;According to this principle, your classes should depend only on abstractions and not on particular implementations.&lt;/p&gt;

&lt;p&gt;This might be hard to visualize, but have the following code example in consideration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ComedyCategory{

}

public class Movie{
    private String name;
    private ComedyCategory comedyCategory;

    public Movie(String name, ComedyCategory comedyCategory){

    }

    public ComedyCategory getCategory(){
        return this.comedyCategory;
    }

    public void setCategory(ComedyCategory comedyCategory){
        this.comedyCategory = comedyCategory;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a closer look at the movie class. It has two fields, which are the movie name and the movie category, which is a specific class with its own specificity and characteristics.&lt;/p&gt;

&lt;p&gt;What happens with the example I just gave you is that our movie class is depending on a specific implementation of a category (in this case the comedy category). With this, we are creating a tight coupling between our Movie class and the ComedeCategory class. We want to avoid these tight couplings.&lt;/p&gt;

&lt;p&gt;One way we can do this is by creating the abstraction/interface of a category and having all existing categories inherit/implement it.&lt;/p&gt;

&lt;p&gt;The following refactoring tries to show this in practice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface Category{

}

public class ComedyCategory implements Category{

}

public class Movie{
    private String name;
    private Category comedyCategory;

    public Movie(String name, Category comedyCategory){

    }

    public ComedyCategory getCategory(){
        return this.comedyCategory;
    }

    public void setCategory(Category comedyCategory){
        this.comedyCategory = comedyCategory;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, now our Movie class only depends on the abstraction of the category and not on a specific implementation of a category. What does this mean in practical terms?&lt;/p&gt;

&lt;p&gt;With our first approach, to instantiate the Movie class, we should have something like &lt;code&gt;Movie joker = new Movie("Joker", new ComedyCategory())&lt;/code&gt;. If we tried and did &lt;code&gt;Movie joker = new Movie("Joker", new DramaCategory())&lt;/code&gt;, we would get an error!&lt;/p&gt;

&lt;p&gt;With our refactored approach, either way would work (the second one would work if DramaCategory implemented Category, of course). We gain flexibility in which category to place our movie at. This flexibility, which can be more generalized in our projects, is one of the major advantages of obeying this principle. Another one is that our applications get more decoupled.&lt;/p&gt;

&lt;p&gt;😁 &lt;strong&gt;I hope this has helped!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's everything for now! Thank you so much for reading. If you are more of a visual learner please refer to &lt;a href="https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898" rel="noopener noreferrer"&gt;this&lt;/a&gt; amazing article, which explains the previous concepts in a more visual way!&lt;/p&gt;

&lt;p&gt;If you have any questions please feel free to drop them off. &lt;br&gt;
Follow me if you want to read more about these kinds of topics!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Social Media Links&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/rafaelcamara96/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/RafaJCamara" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RafaelJCamara" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>systems</category>
      <category>tutorial</category>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
