<?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>Forem: Manu Rodríguez</title>
    <description>The latest articles on Forem by Manu Rodríguez (@manu_coding).</description>
    <link>https://forem.com/manu_coding</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%2F927938%2Fb1aa6372-59f2-492d-8591-7795cf98ba8f.jpg</url>
      <title>Forem: Manu Rodríguez</title>
      <link>https://forem.com/manu_coding</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/manu_coding"/>
    <language>en</language>
    <item>
      <title>Creando objetivos reales</title>
      <dc:creator>Manu Rodríguez</dc:creator>
      <pubDate>Tue, 01 Aug 2023 13:12:07 +0000</pubDate>
      <link>https://forem.com/manu_coding/creando-objetivos-reales-5c2j</link>
      <guid>https://forem.com/manu_coding/creando-objetivos-reales-5c2j</guid>
      <description>&lt;p&gt;Uno de los errores más comunes es el de imponernos objetivos poco realistas o difíciles de alcanzar en un corto plazo de tiempo (terminar tareas grandes en un solo día, refactorizar toda una funcionalidad en una sola sesión, etc…).&lt;/p&gt;

&lt;p&gt;Muchas veces esto lo hacemos de manera inconsciente por querer mejorar o ser más productivos y con la falsa idea de que cuanto más trabajo entreguemos en el menor tiempo seremos mejores desarrolladores, sin pararnos a pensar en los efectos colaterales que puede tener esta decisión. Esto puede provocar varias cosas, por ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Código poco legible o de mala calidad&lt;/li&gt;
&lt;li&gt;Errores en el diseño que pueden provocar otros errores mayores&lt;/li&gt;
&lt;li&gt;Frustración por querer terminar la tarea en el menor tiempo posible&lt;/li&gt;
&lt;li&gt;Sensación de que no avanzamos debido a los errores que han aparecido, lo que puede hacer que la sensación de frustración sea mayor todavía&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1YT4W2op--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odjc7itds5p0xm6glwsj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1YT4W2op--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odjc7itds5p0xm6glwsj.gif" alt="breaking_things" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Las cosas importantes no se construyen en un día
&lt;/h2&gt;

&lt;p&gt;Para evitar esta situación, intenta dividir tu objetivo en otros objetivos más pequeños que te asegures que puedes realizar en un breve espacio de tiempo (horas o incluso días, no tienes que ser un superhéroe). &lt;/p&gt;

&lt;p&gt;Gracias a dividir tu objetivo en objetivos más pequeños, podrás ir viendo algunas mejoras en tu trabajo y en ti mismo como individuo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un código mucho más limpio y de mejor calidad&lt;/li&gt;
&lt;li&gt;Diseño mucho más pensado y meditado para un correcto uso. Se darán menos errores, aunque seguirán existiendo (no somos perfecto, cometeremos errores)&lt;/li&gt;
&lt;li&gt;Satisfacción por cumplir metas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uF_SOwvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2ltvh1ws35jrg5sjy63.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uF_SOwvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2ltvh1ws35jrg5sjy63.gif" alt="building" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uno de los puntos más importantes a mi parecer es el poder tener esa satisfacción de un trabajo terminado y que hemos conseguido entregar. Además nos impulsará a poder seguir con otros objetivos. &lt;/p&gt;

&lt;p&gt;Gracias a poder cumplir estos objetivos más pequeños, veremos como cada vez estamos más cerca de poder cumplir ese objetivo mayor que teníamos al principio como meta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abrazando el equilibrio dinámico
&lt;/h2&gt;

&lt;p&gt;Es muy normal pensar que tenemos siempre que hacer un mínimo de cosas para sentirnos productivos o que tenemos que hacer las tareas en un “tempo” definido porque sino estaremos por debajo de un estándar de productividad y dejaremos de ser productivos. A esto lo podríamos llamar “&lt;strong&gt;equilibrio estático&lt;/strong&gt;” (por ejemplo: todos los días hacer un número determinado de tareas, dedicarle todos los días 1 hora a aprender algo…). Pero ese término se aleja bastante de la realidad.&lt;/p&gt;

&lt;p&gt;Tenemos que ser conscientes de que habrá momentos de nuestra vida que podremos hacer más cosas y otras veces menos (tendremos más energía o menos, habrá situaciones personales o familiares que nos favorezca o no…), pero lo importante es el computo global de cosas que se han hecho a lo largo de un periodo largo de tiempo. Además si estas tareas las realizamos en un “tempo” en el que nos sentimos cómodos para su realización, no nos sentimos con una sobrecarga de trabajo, nos motiva o gusta el trabajo que estamos haciendo… veremos que los resultados son muchísimo mejores en un periodo largo de tiempo. Esta idea la llamó un amigo “equilibrio dinámico”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--enjFmIS7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ul9rkrq8ty6k30xlmb3f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--enjFmIS7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ul9rkrq8ty6k30xlmb3f.gif" alt="balance" width="480" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro de ese equilibrio dinámico, tenemos que ser capaces de dedicar tiempo a poder descansar y dedicarle tiempo a cosas que nos gusten (familia, amigos, hobbies…). No es necesario que estemos constantemente buscando el sentirnos aceptados como desarrolladores por tener más o menos proyectos personales, hacer/grabar cursos, preparar charlas… debemos de recordar que ante todo somos personas, y como personas, tenemos el derecho a sentirnos cansados.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>motivation</category>
      <category>community</category>
    </item>
    <item>
      <title>How to Build Maintainable iOS Apps with Dependency Injection</title>
      <dc:creator>Manu Rodríguez</dc:creator>
      <pubDate>Sat, 29 Apr 2023 18:43:46 +0000</pubDate>
      <link>https://forem.com/manu_coding/how-to-build-maintainable-ios-apps-with-dependency-injection-59om</link>
      <guid>https://forem.com/manu_coding/how-to-build-maintainable-ios-apps-with-dependency-injection-59om</guid>
      <description>&lt;p&gt;Hey there fellow developers! Are you tired of your iOS apps becoming an unmaintainable mess of spaghetti code? &lt;br&gt;
&lt;a href="https://i.giphy.com/media/11uoNyauChZR16/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/11uoNyauChZR16/giphy.gif" alt="Spaguetti!" width="570" height="428"&gt;&lt;/a&gt;&lt;br&gt;
Fear not, for there is a solution: dependency injection. In this article, we'll show you how to use dependency injection to create clean, testable code that's easy to maintain.&lt;/p&gt;

&lt;p&gt;If you're new to dependency injection or just want to improve your iOS development skills, then this article is for you. Let's get started!&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Take Control of Your Code: 5 Key Benefits of Dependency Injection in iOS Programming&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before we dive into the nitty-gritty, let's talk about the benefits of using dependency injection in your iOS apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increased modularity:&lt;/strong&gt; Dependency injection allows objects to be created outside of a class and passed as parameters, making code more modular.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced coupling:&lt;/strong&gt; Injected objects are not coupled to a particular class, making code more flexible and easier to maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased code reuse:&lt;/strong&gt; Injected objects can be reused in multiple classes and applications, reducing code duplication and improving efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier testing:&lt;/strong&gt; Dependency injection makes it easier to perform unit testing on code, as injected objects can be replaced with test objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved performance:&lt;/strong&gt; By avoiding the creation of unnecessary objects, dependency injection can improve the performance of the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Dependency Injection in action!
&lt;/h3&gt;

&lt;p&gt;Let's say you want to retrieve a list of users from a repository. Normally, you might create an instance of the repository directly in your view or presenter class. But with dependency injection, we can create an interface for the repository and pass in an implementation of it at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&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;Next, we create an implementation of the repository that uses an instance of &lt;strong&gt;&lt;code&gt;UserService&lt;/code&gt;&lt;/strong&gt; to retrieve the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UserRepositoryImp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserService&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetchUsers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&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;In this example, &lt;strong&gt;&lt;code&gt;UserRepositoryImp&lt;/code&gt;&lt;/strong&gt; uses an instance of &lt;strong&gt;&lt;code&gt;UserService&lt;/code&gt;&lt;/strong&gt; to retrieve the data. By using dependency injection, we can pass any implementation of &lt;strong&gt;&lt;code&gt;UserService&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;code&gt;UserRepositoryImp&lt;/code&gt;&lt;/strong&gt; and use it to retrieve the data.&lt;/p&gt;

&lt;p&gt;Now, to use &lt;strong&gt;&lt;code&gt;UserRepositoryImp&lt;/code&gt;&lt;/strong&gt; in our application, we can inject it into our view or presenter class, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UserListPresenter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getUsers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
            &lt;span class="c1"&gt;// update view with users&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;In this example, &lt;strong&gt;&lt;code&gt;UserListPresenter&lt;/code&gt;&lt;/strong&gt; uses &lt;strong&gt;&lt;code&gt;UserRepository&lt;/code&gt;&lt;/strong&gt; to retrieve the data. By using dependency injection, we can pass any implementation of &lt;strong&gt;&lt;code&gt;UserRepository&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;code&gt;UserListPresenter&lt;/code&gt;&lt;/strong&gt; and use it to retrieve the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;And… how to do tests with dependency injection?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, to perform unit testing on our code, we can create a mocked implementation of &lt;strong&gt;&lt;code&gt;UserRepository&lt;/code&gt;&lt;/strong&gt; that returns test data and pass it to our test class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MockUserRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"User 1"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"User 2"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"User 3"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&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="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UserListPresenterTests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;XCTestCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testGetUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mockRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MockUserRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;presenter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserListPresenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="kt"&gt;XCTAssertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;XCTAssertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;"User 1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;XCTAssertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;"User 2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;XCTAssertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;"User 3"&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;In this example, we create a mocked implementation of &lt;strong&gt;&lt;code&gt;UserRepository&lt;/code&gt;&lt;/strong&gt; called &lt;strong&gt;&lt;code&gt;MockUserRepository&lt;/code&gt;&lt;/strong&gt;, which returns a list of test users. We then create an instance of &lt;strong&gt;&lt;code&gt;UserListPresenter&lt;/code&gt;&lt;/strong&gt; with &lt;strong&gt;&lt;code&gt;MockUserRepository&lt;/code&gt;&lt;/strong&gt; injected and call the &lt;strong&gt;&lt;code&gt;getUsers()&lt;/code&gt;&lt;/strong&gt; method to retrieve the data. Finally, we check that the data was retrieved correctly.&lt;/p&gt;

&lt;p&gt;I hope this example helps you understand how to use dependency injection to retrieve data from a repository and implement an interface to aid in testing.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>cleancode</category>
      <category>testing</category>
    </item>
    <item>
      <title>Look Around, a window to reality</title>
      <dc:creator>Manu Rodríguez</dc:creator>
      <pubDate>Tue, 04 Oct 2022 16:17:22 +0000</pubDate>
      <link>https://forem.com/manu_coding/look-around-a-window-to-reality-4pl8</link>
      <guid>https://forem.com/manu_coding/look-around-a-window-to-reality-4pl8</guid>
      <description>&lt;p&gt;One of the main innovations that Apple showed at the last WWDC was undoubtedly the improvements in MapKit and the new features that it incorporated in its latest version to provide the user with a better user experience. Perhaps one of the most striking has been the possibility of adding the functionality of Look Around (name given to the Street View developed by Apple) in your application, which allows us to see in 360 a location as if we were on site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To be able to use this new functionality, you must meet the following requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Xcode 14.0 &lt;/li&gt;
&lt;li&gt;iOS 16.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding it to your application
&lt;/h2&gt;

&lt;p&gt;Our first step will be to generate an &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundscene?changes=l_8" rel="noopener noreferrer"&gt;MKLookAroundScene&lt;/a&gt;&lt;/strong&gt;, which we can obtain from a location that we pass to the &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundscenerequest" rel="noopener noreferrer"&gt;MKLookAroundSceneRequest&lt;/a&gt;&lt;/strong&gt; class as shown in the example code:&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 Once we have obtained our &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundscene?changes=l_8" rel="noopener noreferrer"&gt;MKLookAroundScene&lt;/a&gt;&lt;/strong&gt;, we will have to create a &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundviewcontroller?changes=_7" rel="noopener noreferrer"&gt;MKLookAroundViewController&lt;/a&gt;&lt;/strong&gt; (it will be in charge of showing our street view). For it we can do it in the following way:&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Oops... something went wrong
&lt;/h2&gt;

&lt;p&gt;Ok... at this point you are probably thinking that you can use &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundviewcontroller?changes=_7" rel="noopener noreferrer"&gt;MKLookAroundViewController&lt;/a&gt;&lt;/strong&gt; as another UIViewController inside your application and make a classic navigation with this controller (present, push...), surely if you have tried it without reading on you will have found that something strange is happening with your player, like you can't navigate through the streets, the name of the street doesn't appear, etc...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6d1otn20j2jpy2gj5801.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6d1otn20j2jpy2gj5801.gif" alt="All is fine"&gt;&lt;/a&gt;&lt;br&gt;
This is because in order to use this new UIViewController, you cannot use it as if it was a classic UIViewController with its own navigation system. You must use it as an embedded view inside a UIViewController of your view hierarchy as in the following example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Handicaps
&lt;/h2&gt;

&lt;p&gt;A priori it seems a little strange to have to use this functionality in this way and not be able to use &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundviewcontroller?changes=_7" rel="noopener noreferrer"&gt;MKLookAroundViewController&lt;/a&gt;&lt;/strong&gt; as if it were an independent UIViewController, it is something that hopefully Apple will end up solving in future versions of Swift.&lt;br&gt;
&lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundviewcontroller?changes=_7" rel="noopener noreferrer"&gt;MKLookAroundViewController&lt;/a&gt;&lt;/strong&gt; has another handicap at the time of being used and it is the following one: it cannot be used on a view that comes from a modal present, since in the case of being used in that view, this one will appear disabled when our &lt;strong&gt;&lt;a href="https://developer.apple.com/documentation/mapkit/mklookaroundviewcontroller?changes=_7" rel="noopener noreferrer"&gt;MKLookAroundViewController&lt;/a&gt;&lt;/strong&gt; is closed.&lt;br&gt;
If you need to display it over a view that has been displayed through a present, you must display the parent view using the .overFullScreen mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;parentViewController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modalPresentationStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overFullScreen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations on getting this far! You have successfully implemented Look Around in your brand new application. Now you will give your users a better user experience if they want to know what is near a location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl2lt701bzlwdd46ctmss.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl2lt701bzlwdd46ctmss.gif" alt="Great!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
    <item>
      <title>Automating things</title>
      <dc:creator>Manu Rodríguez</dc:creator>
      <pubDate>Tue, 20 Sep 2022 17:44:06 +0000</pubDate>
      <link>https://forem.com/manu_coding/automating-things-3i21</link>
      <guid>https://forem.com/manu_coding/automating-things-3i21</guid>
      <description>&lt;p&gt;Surely if you are more or less new to the world of programming you will have heard one or two things about "CI/CD"  or heard the word "Jenkins" being mentioned.&lt;/p&gt;

&lt;p&gt;If you don't know what those words mean... this is the post for you! I will try to explain everything you need to know about CI/CD in case you want to take your first steps (if you are a veteran you are also welcome).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is CI/CD?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is a code distribution methodology that covers the entire code life cycle. From the time new code is developed and integrated into the existing code, until a version of the application is deployed or distributed with the new code, along with subsequent version monitoring  to check for possible bugs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pER-j30q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrc96gqd1h2ov16sveto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pER-j30q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrc96gqd1h2ov16sveto.png" alt="CI/CD loop phases" width="612" height="289"&gt;&lt;/a&gt;&lt;br&gt;
When we refer to CI/CD we are referring to two different terms or work philosophies based on the automation of tasks, which are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI&lt;/strong&gt; → Continuous Integration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CD&lt;/strong&gt; → Continuous Delivery/Deployment&lt;/p&gt;

&lt;p&gt;Let's look at these two concepts separately.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Continuous Integration, a.k.a. "CI".&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It is very common that in your work environment you do not work alone but you work together with other team members and each of you work on completely different parts of the project. This is most common, and what is even more common is the "merge day", that wonderful day when all the code is brought together to work in harmony.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/26BoCdWySqRcaupWw/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/26BoCdWySqRcaupWw/giphy.gif" alt="https://media.giphy.com/media/26BoCdWySqRcaupWw/giphy.gif" width="480" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But... oh boy! Something went wrong. Too many changes in the project, everyone is in pain and what seemed to be a wonderful day, turns into a gray day of regrets and disappointments.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Continuous integration to the rescue&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Continuous integration (CI) consists of a work philosophy based on integrating the code written by a developer into the main project as soon as possible (it is no good uploading code with bugs, we already know that...).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gL-nQtnc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmiyms1p8c5p0kntlsso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gL-nQtnc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmiyms1p8c5p0kntlsso.png" alt="Dont say works on my machine" width="500" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this way, this code is made accessible to the rest of the teammates, in some cases on the same day.&lt;/p&gt;

&lt;p&gt;To avoid possible errors in the integration, it is necessary to have different tools such as :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit Tests&lt;/li&gt;
&lt;li&gt;Integration Test&lt;/li&gt;
&lt;li&gt;Code analysis&lt;/li&gt;
&lt;li&gt;Code review, etc...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not necessary to incorporate all these tools to your project. They can be incorporated progressively depending on the needs you want to cover or the size of the project. If it is a small project, you may not need to add a code analyzer, such as SonarCloud, SonarQube, DeepSource, etc...&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Continuous Delivery VS Continuous Deployment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes we could make the mistake of not knowing how to differentiate between &lt;strong&gt;continuous delivery&lt;/strong&gt; and &lt;strong&gt;continuous deployment&lt;/strong&gt;. At first glance, both concepts seem very similar since the final objective is the same, to release a version.&lt;/p&gt;

&lt;p&gt;The difference lies in &lt;strong&gt;who performs the action&lt;/strong&gt;, i.e., whether it is the developer or a third party who performs the action of deploying the version (either by pressing a button in Slack, launching a command in the terminal or simply sending a version for review), we are talking about &lt;strong&gt;continuous delivery.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, if the developer or a third party is not required to perform this action but it is executed in a fully automated way, &lt;strong&gt;we speak of continuous deployment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ea-YK163--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dja232exbrq19hn3gafn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ea-YK163--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dja232exbrq19hn3gafn.png" alt="CI/CD phases" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;And who controls this?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this point, you are probably wondering what you need to do to set up your project with CI/CD and see if this works for you or not.&lt;/p&gt;

&lt;p&gt;It is very common to think that you need a whole team of people to set up an IC/DC ecosystem for your application, to set up a big rack of machines connected to a big network with a very high connection speed and to do super complicated and complex tasks like you are entering the Matrix. And no, you're not.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;The developer also set up pipelines&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Normally we tend to think that this is a task that should be done by the infrastructure or SRE team in the development team, but I believe that this is not the case.&lt;/p&gt;

&lt;p&gt;The infrastructure team should provide you with the environment to set up your workflows (virtual machine, Kubernetes, etc...), but developers should be autonomous enough to be able to set up the workflows or pipelines by themselves and make the necessary modifications.&lt;/p&gt;

&lt;p&gt;Let's think about it more carefully... the developer is the one who best knows the requirements of the application environment, what he needs to test, how he needs to test it, how he needs to generate the versions and so on and so forth. In the same way, the infrastructure team knows much better all the security aspects of the VPN you use to work, where the hosted repository is located, etc... That is why I consider that it is the responsibility of the developer to set up the pipelines or workflows since he/she is ultimately responsible for making sure that his/her code works in the best possible way.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Okay, so what do I do if I can't maintain the IC/DC system myself?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nowadays there are very easy to use tools that allow you to have a CI/CD ecosystem in a few minutes by editing just one file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;&lt;/strong&gt; (includes support for iOS) allows you in a few steps - and by setting up a YAML file - to create a whole ecosystem of workflows that will be executed when a pull request is opened, a tag is created, a commit is uploaded to a branch, etc...&lt;/p&gt;

&lt;p&gt;Here’s is an example of how we can set up a simple workflow in &lt;strong&gt;&lt;a href="https://github.com/features/actions"&gt;Github Action&lt;/a&gt;&lt;/strong&gt; to run some tests of our application on different versions of MacOS&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="c1"&gt;# This is a basic workflow to help you get started with Actions&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;Testing&lt;/span&gt;

&lt;span class="c1"&gt;# Controls when the workflow will run&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Triggers the workflow on push or pull request events but only for the "master" branch&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Allows you to run this workflow manually from the Actions tab&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="c1"&gt;# A workflow run is made up of one or more jobs that can run sequentially or in parallel&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;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fail-fast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
        &lt;span class="na"&gt;xcode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;latest-stable&lt;/span&gt;
        &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
            &lt;span class="na"&gt;xcode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&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;macos-${{ matrix.macos }}&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get Sources&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 Xcode&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;maxim-lobanov/setup-xcode@v1.4.0&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;xcode-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;13.1"&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;Build 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;swift build -v&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;Run tests&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;swift test --enable-code-coverage -v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from &lt;a href="https://github.com/features/actions"&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/a&gt; there are many other options, such as: &lt;strong&gt;&lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://www.bitrise.io/"&gt;Bitrise&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://codemagic.io/start/"&gt;CodeMagic&lt;/a&gt;&lt;/strong&gt;... you simply have to find the solution that best suits you and start testing!&lt;/p&gt;

&lt;p&gt;I can only leave you with one last opinion about integrating CI/CD to your project, and here it is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lTsbb2yT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkqm822mmbew6ck4nqeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lTsbb2yT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkqm822mmbew6ck4nqeo.png" alt="CI/CD makes all better" width="800" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>mobile</category>
      <category>agile</category>
    </item>
  </channel>
</rss>
