<?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: JR Saucedo</title>
    <description>The latest articles on DEV Community by JR Saucedo (@betoflakes).</description>
    <link>https://dev.to/betoflakes</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%2F26087%2F2912a96d-cdef-48a4-8f4c-b61788cea98e.jpg</url>
      <title>DEV Community: JR Saucedo</title>
      <link>https://dev.to/betoflakes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/betoflakes"/>
    <language>en</language>
    <item>
      <title>Registro 004-1. Domina Flutter con Clean Architecture: Integración de Supabase y Repositorios Simplificada</title>
      <dc:creator>JR Saucedo</dc:creator>
      <pubDate>Sun, 22 Sep 2024 04:23:49 +0000</pubDate>
      <link>https://dev.to/betoflakes/registro-004-1-domina-flutter-con-clean-architecture-integracion-de-supabase-y-repositorios-simplificada-40bd</link>
      <guid>https://dev.to/betoflakes/registro-004-1-domina-flutter-con-clean-architecture-integracion-de-supabase-y-repositorios-simplificada-40bd</guid>
      <description>&lt;p&gt;Continuando con el progreso de nuestro proyecto, ya sabemos cómo se vería la configuración inicial de nuestro &lt;code&gt;service locator&lt;/code&gt; para la inyección de dependencias. Ahora, vayamos a algo menos estándar y más relacionado con las características específicas del proyecto, donde comenzaremos a aplicar la &lt;code&gt;clean architecture&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Cuando iniciamos un proyecto y aún no contamos con toda la estructura clara de cómo será, lo que sí solemos tener en mente es nuestro proceso de &lt;code&gt;autenticación&lt;/code&gt;. Aunque en nuestro caso sabemos hacia dónde vamos, en este proyecto utilizaremos &lt;code&gt;Supabase&lt;/code&gt; y sus capacidades de control de acceso.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;features/user&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Primero, creamos nuestros directorios a utilizar:&lt;/p&gt;

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

&lt;p&gt;Aquí es donde comenzamos a aplicar nuestra &lt;code&gt;clean architecture&lt;/code&gt;, dividiendo los directorios y sus responsabilidades. Personalmente, me gusta comenzar en orden alfabético la creación de archivos, así que empecemos por la fuente de datos: &lt;code&gt;data&lt;/code&gt;, donde manejaremos todo lo relacionado con la obtención de información del usuario. Primero crearemos el modelo, no muy alfabéticamente de mi parte, pero luego entenderán por qué.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;features/user/data/models&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Aquí definimos lo que esperamos recibir de nuestra instancia de &lt;code&gt;Supabase&lt;/code&gt; para el perfil de usuario:&lt;/p&gt;

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

&lt;p&gt;Desglosemos lo que tenemos aquí:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usamos la anotación &lt;code&gt;@freezed&lt;/code&gt;, que nos ayudará a crear todos los métodos necesarios para nuestro modelo, cumpliendo con los estándares de Dart, aunque no se usen todos.&lt;/li&gt;
&lt;li&gt;Declaramos nuestra clase y la unimos a nuestro &lt;code&gt;mixin&lt;/code&gt; con todos estos métodos.&lt;/li&gt;
&lt;li&gt;En nuestro primer &lt;code&gt;factory&lt;/code&gt;, definimos los campos que tendrá nuestro modelo.&lt;/li&gt;
&lt;li&gt;Por último, creamos un &lt;code&gt;factory fromJson&lt;/code&gt;, útil para transformar datos en formato &lt;code&gt;JSON&lt;/code&gt; (de APIs, SDKs, etc.) a una &lt;code&gt;data class&lt;/code&gt; compatible con &lt;code&gt;Dart&lt;/code&gt;, que se generará automáticamente gracias a la anotación &lt;code&gt;@freezed&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf0gfpajf28gwhmrrjbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf0gfpajf28gwhmrrjbw.png" alt="Modelo recién creado" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Al crear el modelo, verás que el documento se llena de errores, pero no pasa nada. Para que todo funcione, debemos correr el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dart run build_runner build &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Si estás creando varios modelos, puedes correr un &lt;code&gt;watch&lt;/code&gt; para que se creen automáticamente:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dart run build_runner watch &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;features/user/data/data_source&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Ya tenemos nuestro modelo, continuemos con nuestro &lt;code&gt;data_source&lt;/code&gt;. Este será otro archivo Dart, llamado &lt;code&gt;user_source&lt;/code&gt;, que contendrá todas las peticiones a &lt;code&gt;Supabase&lt;/code&gt; relacionadas con el usuario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz7sv2uookphsmduwkna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz7sv2uookphsmduwkna.png" alt="Estructura de UserSource" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como ves, muchos de nuestros métodos devuelven un &lt;code&gt;UserModel&lt;/code&gt;. Para evitar más errores, creamos el modelo antes de seguir con esta parte. Ahora vayamos método por método, agregando nuestra lógica:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfgy51e2geeelw8qg8yd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfgy51e2geeelw8qg8yd.png" alt="Registro de usuario" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para iniciar sesión, primero necesitamos una cuenta. Una opción es hacerlo con un correo electrónico y contraseña. Además, utilizaremos &lt;code&gt;gravatar&lt;/code&gt; para generar imágenes de perfil de los usuarios, evitando así gestionar imágenes directamente y evitando posibles problemas legales.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujfm31zhf35m12pqeuhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujfm31zhf35m12pqeuhv.png" alt="Registro de perfil" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por último, creamos un registro en nuestra tabla &lt;code&gt;profiles&lt;/code&gt;, donde se almacenará el perfil público del usuario para enlazarlo con sus partidas y otros usos. Aquí tienes la estructura de la tabla en &lt;code&gt;Supabase&lt;/code&gt;:&lt;/p&gt;

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

&lt;p&gt;Con esto, ya tenemos nuestro método de registro. Ahora podemos iniciar sesión con este otro método:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwyfhyl7fthh7zhohqpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwyfhyl7fthh7zhohqpf.png" alt="Inicio de Sesión" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es un método sencillo, donde nuestro factory &lt;code&gt;fromJson&lt;/code&gt; entra en acción, transformando la respuesta del SDK a una &lt;code&gt;data class&lt;/code&gt; compatible con Dart.&lt;/p&gt;

&lt;p&gt;Para no hacer más extenso este artículo, continuaremos con estos métodos en el futuro para completar nuestra &lt;code&gt;feature&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuración de Inyección
&lt;/h4&gt;

&lt;p&gt;Como mencionamos antes, en el constructor de la clase indicamos que recibirá un &lt;code&gt;SupabaseClient&lt;/code&gt;. Pero, ¿de dónde lo recibirá? Esto lo hacemos con cada elemento de nuestra arquitectura a través del &lt;code&gt;service locator&lt;/code&gt; o inyector de dependencias.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;UserSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;SupabaseClient&lt;/span&gt; &lt;span class="n"&gt;_client&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;Utilizaremos un &lt;code&gt;registerFactory&lt;/code&gt; para agregar nuestro &lt;code&gt;UserSource&lt;/code&gt; y su dependencia requerida en el constructor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1ithzxuzbchiw6pn2j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1ithzxuzbchiw6pn2j0.png" alt="Inyección de Dependencias" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El cual se vería algo así, hasta ahora, donde se ve que le decimos qué dependencia recibe con un tipo en nuestro &lt;code&gt;service locator&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;features/user/[data/domain]/repositories&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Ahora conectemos nuestras capas &lt;code&gt;data&lt;/code&gt; y &lt;code&gt;domain&lt;/code&gt;. Para esto, primero creemos nuestro repositorio en la capa &lt;code&gt;domain&lt;/code&gt;. Esta será una clase abstracta donde solo declaramos los métodos que utilizaremos en &lt;code&gt;domain&lt;/code&gt;, los cuales luego implementaremos en nuestro repositorio de implementación.&lt;/p&gt;

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

&lt;p&gt;Aquí está, y si no conoces el paquete &lt;a href="https://pub.dev/packages/dartz" rel="noopener noreferrer"&gt;&lt;code&gt;dartz&lt;/code&gt;&lt;/a&gt;, te lo presento. Es una útil herramienta para controlar los estados de error en nuestras diferentes capas. Nuestro método espera dos posibles respuestas: un error o la data correcta, lo cual nos permitirá atrapar estas respuestas y mostrar el estado adecuado en nuestra app.&lt;/p&gt;

&lt;p&gt;Para manejar errores, en este caso, crearemos una clase de ayuda llamada &lt;code&gt;Failure&lt;/code&gt;, la cual mediante extensiones nos permitirá gestionar diversos errores. Esta la crearemos en &lt;code&gt;core/common/exceptions&lt;/code&gt;:&lt;/p&gt;

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

&lt;p&gt;Aquí utilizamos otra librería muy útil llamada &lt;a href="https://pub.dev/packages/equatable" rel="noopener noreferrer"&gt;&lt;code&gt;Equatable&lt;/code&gt;&lt;/a&gt;, la cual nos facilita transportar varios campos en nuestra clase y manejar de forma más limpia las comparaciones de clases y valores.&lt;/p&gt;

&lt;p&gt;Ahora bien, tenemos en una misma clase dos tipos de error: &lt;code&gt;SupaBaseException&lt;/code&gt; y &lt;code&gt;Error&lt;/code&gt;, los cuales son extensiones de la misma clase. Nuestros métodos podrían devolver cualquiera de ellos. Además, el campo &lt;code&gt;exception&lt;/code&gt; es opcional, ya que no siempre se cumple.&lt;/p&gt;

&lt;p&gt;Para finalizar, necesitamos nuestra &lt;code&gt;UserEntity&lt;/code&gt;, ya que, como sabemos, en las capas posteriores no deberíamos utilizar los modelos de la capa anterior. Entonces, pasemos a crearla:&lt;/p&gt;

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

&lt;p&gt;Podemos ver que tiene los mismos campos que nuestro modelo, pero más simplificado. A partir de esta capa, no necesitamos realizar más transformaciones ni cambios. Todo es inmutable a partir de este punto.&lt;/p&gt;

&lt;p&gt;Regresemos a la capa &lt;code&gt;data&lt;/code&gt; en nuestro directorio &lt;code&gt;repositories&lt;/code&gt; y creemos nuestro repositorio de implementación &lt;code&gt;user_repo_impl.dart&lt;/code&gt; con lo siguiente:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:dartz/dartz.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../../../../core/common/exceptions/failure.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../../domain/entities/user.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../../domain/repositories/user_repo.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'../data_source/user_source.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepoImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;UserRepoImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_userDataSource&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;UserSource&lt;/span&gt; &lt;span class="n"&gt;_userDataSource&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Either&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserEntity&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_userDataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUser&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;Right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SupaBaseException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&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="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Either&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInWithEmailAndPassword&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;email&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;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_userDataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&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;Right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SupaBaseException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&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="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&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;_userDataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Either&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signUpWithEmailAndPassword&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;email&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;password&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_userDataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signUpWithEmailAndPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;password&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="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SupaBaseException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&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;Con esto, hacemos la conexión entre capas, logrando pasar nuestros datos desde su fuente hasta las capas posteriores. Ahora, toca agregar la inyección de dependencias correspondiente, ya que nuestra implementación espera recibir el &lt;code&gt;data_source&lt;/code&gt; llamado &lt;code&gt;UserSource&lt;/code&gt; como dependencia. Para eso hacemos lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xph5lvmmazskkql95tc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xph5lvmmazskkql95tc.png" alt="UserRepo en service locator" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí podemos notar algo peculiar: declaramos como tipo principal &lt;code&gt;UserRepository&lt;/code&gt;, pero en el factory inicializamos nuestro &lt;code&gt;UserReposImpl&lt;/code&gt;, que es el que necesita la dependencia &lt;code&gt;UserSource&lt;/code&gt;. Sin embargo, en la siguiente capa &lt;code&gt;domain/use_cases&lt;/code&gt;, utilizaremos &lt;code&gt;UserRepository&lt;/code&gt;.&lt;/p&gt;



&lt;p&gt;Si estás siguiendo el proceso, es posible que te hayas encontrado con el siguiente error:&lt;/p&gt;

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

&lt;p&gt;Los métodos del repositorio están esperando como respuesta un tipo &lt;code&gt;UserEntity&lt;/code&gt;, pero nosotros estamos enviando un &lt;code&gt;UserModel&lt;/code&gt;. Este error lo abordaremos en el siguiente artículo, ya que, como pueden ver, hasta ahora hemos hecho bastante trabajo, y este post se ha vuelto mucho más largo en comparación con mis registros anteriores.&lt;/p&gt;

&lt;p&gt;Para resolverlo, hay varios caminos, y los analizaremos en la segunda parte de este blog.&lt;/p&gt;

&lt;p&gt;Gracias por acompañarme hasta aquí, y espero que haya sido claro. ¡Nos vemos en la siguiente entrega!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/devsignersmx" rel="noopener noreferrer"&gt;
        devsignersmx
      &lt;/a&gt; / &lt;a href="https://github.com/devsignersmx/rps-public" rel="noopener noreferrer"&gt;
        rps-public
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;RPS Rumble&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Proyecto donde aplicaremos la &lt;code&gt;Clean Architecture&lt;/code&gt; con &lt;code&gt;dependency injection&lt;/code&gt; y &lt;code&gt;bloc&lt;/code&gt;. Encuentra todo los articulos en la serie de:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/betoflakes/series/28447" rel="nofollow"&gt;De Cero a Flutter: Mi Viaje para Construir una App y Compartir lo Aprendido&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/devsignersmx/rps-public" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>spanish</category>
      <category>flutter</category>
      <category>dart</category>
      <category>supabase</category>
    </item>
    <item>
      <title>Retgistro 003 — Flutter desde Cero: Simplificando tu main.dart y Dominando la Inyección de Dependencias</title>
      <dc:creator>JR Saucedo</dc:creator>
      <pubDate>Wed, 28 Aug 2024 20:25:18 +0000</pubDate>
      <link>https://dev.to/betoflakes/retgistro-003-flutter-desde-cero-simplificando-tu-maindart-y-dominando-la-inyeccion-de-dependencias-22j5</link>
      <guid>https://dev.to/betoflakes/retgistro-003-flutter-desde-cero-simplificando-tu-maindart-y-dominando-la-inyeccion-de-dependencias-22j5</guid>
      <description>&lt;p&gt;Luego de platicar sobre la planeación y estipular la arquitectura a utilizar, porque como bien sabemos, y si no te lo había contado, aplicar una arquitectura como Clean Architecture puede tener muchas variantes. Al final, más que una estructura rígida, termina siendo una filosofía que podemos adaptar según las necesidades e interpretaciones, siempre cumpliendo con sus principios. Pero bueno, si queremos profundizar más en eso, podemos leer el artículo anterior: &lt;a href="https://dev.to/betoflakes/registro-002-organizando-el-codigo-clean-architecture-en-accion-para-tu-proyecto-flutter-200m"&gt;Registro 002&lt;/a&gt;. Porque ahora sí, en este artículo, comenzaremos a escribir código.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssgl1jo1j5ppa9o63ptv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssgl1jo1j5ppa9o63ptv.png" alt="Image description" width="183" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Inyeccion de dependencias y primeros ajustes.
&lt;/h3&gt;

&lt;p&gt;Como lo platicamos, esta sería nuestra estructura; no cambia mucho a lo normal. Contamos con un archivo main.dart y otros directorios. Pero en este caso, limpiaremos nuestro archivo y le quitaremos unas cuantas responsabilidades que no sean las de inicialización.&lt;/p&gt;

&lt;p&gt;Originalmente, nuestro archivo main.dart suele venir así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&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="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// This widget is the root of your application.&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&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;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Demo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// This is the theme of your application.&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
        &lt;span class="c1"&gt;// TRY THIS: Try running your application with "flutter run". You'll see&lt;/span&gt;
        &lt;span class="c1"&gt;// the application has a purple toolbar. Then, without quitting the app,&lt;/span&gt;
        &lt;span class="c1"&gt;// try changing the seedColor in the colorScheme below to Colors.green&lt;/span&gt;
        &lt;span class="c1"&gt;// and then invoke "hot reload" (save your changes or press the "hot&lt;/span&gt;
        &lt;span class="c1"&gt;// reload" button in a Flutter-supported IDE, or press "r" if you used&lt;/span&gt;
        &lt;span class="c1"&gt;// the command line to start the app).&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
        &lt;span class="c1"&gt;// Notice that the counter didn't reset back to zero; the application&lt;/span&gt;
        &lt;span class="c1"&gt;// state is not lost during the reload. To reset the state, use hot&lt;/span&gt;
        &lt;span class="c1"&gt;// restart instead.&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
        &lt;span class="c1"&gt;// This works for code too, not just values: Most code changes can be&lt;/span&gt;
        &lt;span class="c1"&gt;// tested with just a hot reload.&lt;/span&gt;
        &lt;span class="nl"&gt;colorScheme:&lt;/span&gt; &lt;span class="n"&gt;ColorScheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromSeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seedColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deepPurple&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;useMaterial3:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Demo Home Page'&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;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// This widget is the home page of your application. It is stateful, meaning&lt;/span&gt;
  &lt;span class="c1"&gt;// that it has a State object (defined below) that contains fields that affect&lt;/span&gt;
  &lt;span class="c1"&gt;// how it looks.&lt;/span&gt;

  &lt;span class="c1"&gt;// This class is the configuration for the state. It holds the values (in this&lt;/span&gt;
  &lt;span class="c1"&gt;// case the title) provided by the parent (in this case the App widget) and&lt;/span&gt;
  &lt;span class="c1"&gt;// used by the build method of the State. Fields in a Widget subclass are&lt;/span&gt;
  &lt;span class="c1"&gt;// always marked "final".&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyHomePageState&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="nc"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&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;int&lt;/span&gt; &lt;span class="n"&gt;_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_incrementCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// This call to setState tells the Flutter framework that something has&lt;/span&gt;
      &lt;span class="c1"&gt;// changed in this State, which causes it to rerun the build method below&lt;/span&gt;
      &lt;span class="c1"&gt;// so that the display can reflect the updated values. If we changed&lt;/span&gt;
      &lt;span class="c1"&gt;// _counter without calling setState(), then the build method would not be&lt;/span&gt;
      &lt;span class="c1"&gt;// called again, and so nothing would appear to happen.&lt;/span&gt;
      &lt;span class="n"&gt;_counter&lt;/span&gt;&lt;span class="o"&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="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This method is rerun every time setState is called, for instance as done&lt;/span&gt;
    &lt;span class="c1"&gt;// by the _incrementCounter method above.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// The Flutter framework has been optimized to make rerunning build methods&lt;/span&gt;
    &lt;span class="c1"&gt;// fast, so that you can just rebuild anything that needs updating rather&lt;/span&gt;
    &lt;span class="c1"&gt;// than having to individually change instances of widgets.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// TRY THIS: Try changing the color here to a specific color (to&lt;/span&gt;
        &lt;span class="c1"&gt;// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar&lt;/span&gt;
        &lt;span class="c1"&gt;// change color while the other colors stay the same.&lt;/span&gt;
        &lt;span class="nl"&gt;backgroundColor:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;colorScheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inversePrimary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Here we take the value from the MyHomePage object that was created by&lt;/span&gt;
        &lt;span class="c1"&gt;// the App.build method, and use it to set our appbar title.&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Center is a layout widget. It takes a single child and positions it&lt;/span&gt;
        &lt;span class="c1"&gt;// in the middle of the parent.&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="c1"&gt;// Column is also a layout widget. It takes a list of children and&lt;/span&gt;
          &lt;span class="c1"&gt;// arranges them vertically. By default, it sizes itself to fit its&lt;/span&gt;
          &lt;span class="c1"&gt;// children horizontally, and tries to be as tall as its parent.&lt;/span&gt;
          &lt;span class="c1"&gt;//&lt;/span&gt;
          &lt;span class="c1"&gt;// Column has various properties to control how it sizes itself and&lt;/span&gt;
          &lt;span class="c1"&gt;// how it positions its children. Here we use mainAxisAlignment to&lt;/span&gt;
          &lt;span class="c1"&gt;// center the children vertically; the main axis here is the vertical&lt;/span&gt;
          &lt;span class="c1"&gt;// axis because Columns are vertical (the cross axis would be&lt;/span&gt;
          &lt;span class="c1"&gt;// horizontal).&lt;/span&gt;
          &lt;span class="c1"&gt;//&lt;/span&gt;
          &lt;span class="c1"&gt;// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"&lt;/span&gt;
          &lt;span class="c1"&gt;// action in the IDE, or press "p" in the console), to see the&lt;/span&gt;
          &lt;span class="c1"&gt;// wireframe for each widget.&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'You have pushed the button this many times:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;$_counter&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textTheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headlineMedium&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;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_incrementCounter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;tooltip:&lt;/span&gt; &lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// This trailing comma makes auto-formatting nicer for build methods.&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;Haremos un cambio bastante fuerte, quitando todo lo que no necesitamos que esté aquí y, como mencionamos, solo dejaremos lo necesario para inicializar nuestra app. Llegamos a esto:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:error_stack/error_stack.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/foundation.dart'&lt;/span&gt; &lt;span class="kd"&gt;show&lt;/span&gt; &lt;span class="n"&gt;kDebugMode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:supabase_flutter/supabase_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'core/app/app.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'core/service_locator.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&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;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;url:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s"&gt;'SUPABASE_URL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;anonKey:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s"&gt;'SUPABASE_ANON_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;realtimeClientOptions:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;RealtimeClientOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;logLevel:&lt;/span&gt; &lt;span class="n"&gt;kDebugMode&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;RealtimeLogLevel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RealtimeLogLevel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&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;await&lt;/span&gt; &lt;span class="n"&gt;setupServiceLocator&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;ErrorStack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MainApp&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;Encontramos quizás código conocido para todos y otro no tan conocido.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WidgetsFlutterBinding.ensureInitialized();&lt;/code&gt; Con este paso, nos aseguramos de que el Flutter engine esté listo para comenzar nuestras acciones, especialmente nuestra conexión con Supabase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inicializamos nuestra conexión con Supabase, trayendo de nuestro environment las variables necesarias. A su vez, le designamos un logLevel a nuestras comunicaciones en tiempo real.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Para hacer funcionar String.fromEnvironment() cuando corramos nuestra app y hagamos build, tendremos que agregar nuestras variables como argumentos: --dart-define=SUPABASE_URL=*****, separando un argumento por cada variable de ambiente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Si estás corriendo en debug directamente desde VS Code, estos argumentos extras puedes agregarlos en el launch.json:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x57bvk6ud8aky1uxhbu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x57bvk6ud8aky1uxhbu.png" alt="Image description" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si estas usando Android Studio, entras a la configuración de debugging y agregas los argumentos extras:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wcxrgwyi7rhmft1kco4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wcxrgwyi7rhmft1kco4.png" alt="Image description" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Luego, iniciamos nuestro serviceLocator, que se encargará de la inyección de dependencias.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tenemos una librería que nos muestra mayor información cuando tenemos errores que no estamos capturando, muy útil: ErrorStack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Al final, contamos con nuestro clásico runApp.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Service Locator
&lt;/h3&gt;

&lt;p&gt;Luego de ver los detalles en main.dart, podemos pasar al archivo que es un tanto diferente a lo que podríamos estar acostumbrados a ver en nuestros proyectos de Flutter. Para el caso de la inyección de dependencias, utilizaremos la librería get_it. La inicialización de este es muy sencilla, al menos al inicio. Creamos un archivo service_locator.dart en nuestro directorio core.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:get_it/get_it.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt; &lt;span class="n"&gt;sl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setupServiceLocator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Como bien podemos ver, el método setupServiceLocator es el que invocamos en main.dart y, en su caso, la instancia sl es la que llamaremos para acceder a las dependencias. Vamos a configurar una dependencia que es la principal a utilizar, en este caso el cliente de Supabase, aunque en otros proyectos podría ser el cliente de Dio o el cliente HTTP que utilices.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuración de dependencias - Supabase
&lt;/h3&gt;

&lt;p&gt;La instancia de Supabase ya la inicializamos en el main.dart, ahora hagámosla accesible a través de nuestro inyector. Creamos un archivo dentro de core/services y lo llamaremos supabase_client.dart. En él colocaremos una clase donde accederemos a las librerías que necesitamos de Supabase.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:supabase_flutter/supabase_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupabaseNetwork&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;SupabaseNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_supabase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;Supabase&lt;/span&gt; &lt;span class="n"&gt;_supabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;SupabaseClient&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&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;Por cuestiones de naming, no pudimos llamar nuestra clase igual que nuestro archivo, pero este archivo va más como ejemplo. Porque si bien podríamos agregarlo directo a nuestro serviceLocator, como bien mencioné, para ejemplificar en nuestro proyecto, estamos haciéndolo así.&lt;/p&gt;

&lt;p&gt;Luego de que tenemos nuestra clase, la registramos en nuestro serviceLocator.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:get_it/get_it.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:supabase_flutter/supabase_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'services/supabase_client.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt; &lt;span class="n"&gt;sl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setupServiceLocator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;sl&lt;/span&gt;
    &lt;span class="c1"&gt;//Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SupabaseClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SupabaseNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&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;En este caso, lo registramos como factory, para acceder a una nueva instancia con cada get que realicemos de la dependencia. Luego, con otros tipos, usaremos otros tipos de registro para poder compartir el mismo estado de las dependencias según el caso.&lt;/p&gt;



&lt;p&gt;Creo que por este artículo ha sido bastante información. En la siguiente entrega abordaremos la creación del features/users, donde veremos la inyección de la dependencia y conexión con data_source, repos, y bloc en sus diferentes ubicaciones, así como también el registro de esas dependencias.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/devsignersmx" rel="noopener noreferrer"&gt;
        devsignersmx
      &lt;/a&gt; / &lt;a href="https://github.com/devsignersmx/rps-public" rel="noopener noreferrer"&gt;
        rps-public
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;RPS Rumble&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Proyecto donde aplicaremos la &lt;code&gt;Clean Architecture&lt;/code&gt; con &lt;code&gt;dependency injection&lt;/code&gt; y &lt;code&gt;bloc&lt;/code&gt;. Encuentra todo los articulos en la serie de:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/betoflakes/series/28447" rel="nofollow"&gt;De Cero a Flutter: Mi Viaje para Construir una App y Compartir lo Aprendido&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/devsignersmx/rps-public" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>flutter</category>
      <category>spanish</category>
      <category>supabase</category>
      <category>dependencyinjection</category>
    </item>
    <item>
      <title>Registro 002 - Organizando el Código: Clean Architecture en Acción para tu Proyecto Flutter</title>
      <dc:creator>JR Saucedo</dc:creator>
      <pubDate>Tue, 13 Aug 2024 01:15:09 +0000</pubDate>
      <link>https://dev.to/betoflakes/registro-002-organizando-el-codigo-clean-architecture-en-accion-para-tu-proyecto-flutter-200m</link>
      <guid>https://dev.to/betoflakes/registro-002-organizando-el-codigo-clean-architecture-en-accion-para-tu-proyecto-flutter-200m</guid>
      <description>&lt;p&gt;Como hemos visto luego de planear ya podemos comenzar escribir nuestro codigo, y si bien no quisiera entrar en temas muy iniciales de flutter y demas, si podemos obviar algunas cosas que necesitamos para comenzar:&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisitos
&lt;/h2&gt;

&lt;p&gt;Comenzaremos con que es importante tener Flutter instalado y Android Studio, entre otros pasos que puedes revisar aquí, primeramente para crear nuestro proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter create &lt;span class="o"&gt;{&lt;/span&gt;nombre de directorio&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--project-name&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;nombre de nuestro app&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego agregaremos las librerias que utilizaremos en nuestro proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add supabase_flutter bloc flutter_bloc dartz get_it dio flutter_gen google_fonts error_stack cached_network_image equatable flutter_dotenv flutter_screenutil freezed_annotation gap go_router json_annotation pull_to_refresh skeletonizer toastification google_sign_in flutter_gravatar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a. Las librerias de soporte en el desarrollo que usaremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add &lt;span class="nt"&gt;--dev&lt;/span&gt; bloc_test build_runner flutter_gen_runner freezed json_serializable mockito mocktail
Estructura
Como hemos mencionado, trabajaremos con la Clean Architecture, por lo que debemos organizar nuestros directorios de manera específica para no perdernos y cumplir con cada punto de dicha metodología. A continuación, implementaremos una estructura que me ha servido y que considero la más fácil de usar, aunque en internet encontrarás diferentes maneras de aplicar esta arquitectura.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Estructura
&lt;/h2&gt;

&lt;p&gt;Comencemos con el primer nivel de directorios:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa2jrc7o7cs9p5y7x8vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa2jrc7o7cs9p5y7x8vr.png" alt="Image description" width="183" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;core&lt;/code&gt;: Aquí almacenaremos servicios y widgets comunes o compartidos.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;features&lt;/code&gt;: Donde organizaremos las secciones principales de nuestra app.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gen&lt;/code&gt;: Es un directorio autogenerado que utiliza la librería flutter_gen para los assets que usemos. No es necesario generarlo manualmente, ya que se autogenerará más tarde.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.dart&lt;/code&gt;: Contendrá nuestra función main, que correrá la app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdj4c6hw2yqavawgq46c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdj4c6hw2yqavawgq46c.png" alt="Image description" width="206" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Core
&lt;/h3&gt;

&lt;p&gt;Como mencionamos, nuestro directorio core almacenará todo lo relacionado con servicios y widgets compartidos en toda la app.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app&lt;/code&gt;: Almacena nuestra aplicación, donde agregaremos todo lo relacionado con las configuraciones de nuestra clase MainApp. Usualmente, se encuentra dentro de main.dart, pero es más limpio extraerla a su propio archivo.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;routes&lt;/code&gt;: La configuración de nuestras rutas, donde usaremos GoRoute.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;theme&lt;/code&gt;: Nuestra clase para configurar todo nuestro tema.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;common&lt;/code&gt;: Contendrá todos nuestros widgets compartidos y clases que utilizaremos en servicios o dentro de la misma Clean Architecture.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;services&lt;/code&gt;: Aquí irán nuestras clases de clientes de comunicación con las diferentes APIs que utilicemos o clientes HTTP. En nuestro proyecto, utilizaremos Supabase.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;service_locator&lt;/code&gt;: Nuestra clase encargada de la inyección de dependencias.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Nuestra organización estará centrada en funcionalidades (features), por lo que dentro de este directorio las dividiremos por nombre, y dentro colocaremos nuestra estructura de Clean Architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5e1xpug1izqxk3zbfkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5e1xpug1izqxk3zbfkm.png" alt="Image description" width="191" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data&lt;/code&gt;: Concentra la obtención de información de fuentes externas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;data_source&lt;/code&gt;: Contiene las clases que utilizan nuestro servicio de API para obtener la información a utilizar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;models&lt;/code&gt;: Son nuestras estructuras de datos primitivas, donde hacemos la transformación de JSON a data class de Dart. Principalmente, utilizamos este primer paso para hacer más sencillo su manejo dentro de nuestra app. Suelen ser una extensión de nuestras entities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;repositories&lt;/code&gt;: Aquí se almacenan las implementaciones de los repositorios que se encuentran en domain. Es crucial que estas implementaciones se mantengan en la capa data para cumplir con los principios de la Clean Architecture.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;domain&lt;/code&gt;: Concentra nuestra lógica ya transformada y compatible con nuestra app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;entities&lt;/code&gt;: Son nuestros modelos, pero ya listos para su manejo dentro de la app. A partir de este punto, solo usamos las entities para mostrar nuestros datos en la app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;repositories&lt;/code&gt;: Son la representación abstracta de nuestros repositorios, previamente implementados en la capa data. Mantener los repositorios en forma de interfaces en esta capa asegura la independencia de la lógica de negocio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;use_cases&lt;/code&gt;: Son clases con propiedades que llaman a nuestros repositorios con un método call(). Entonces, por cada método de nuestro repositorio, existirá un use_case.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;presentation&lt;/code&gt;: Engloba la parte visual de nuestra app, donde ahora sí utilizaremos los datos listos y “sanitizados” de nuestra app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bloc&lt;/code&gt;: Consumirá nuestros use_cases y hará las actualizaciones de estado de nuestra app, según las respuestas que reciba, ya sean satisfactorias o errores. Es importante mantener la lógica de presentación aislada de los detalles específicos de los casos de uso.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pages&lt;/code&gt;: Teniendo en mente el pensamiento de diseño atómico de nuestros componentes, esta parte almacenará las moléculas que se complementarán de widgets que esperan recibir la data para mostrarla.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;widgets&lt;/code&gt;: Son la parte más pequeña de nuestra app, fragmentos que esperan recibir data para presentarla. A su vez, ejecutan acciones de nuestro bloc para recibirla o hacer cambios en nuestra app, como formularios, botones o URLs de imágenes para mostrarlas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Es crucial recordar que la organización debe seguir principios claros de separación de responsabilidades y uso de abstracciones para mantener la integridad de la Clean Architecture.&lt;/p&gt;

&lt;p&gt;Esto ha sido un monton de información que degerir, pero es mucho más sencillo de lo que parece. En nuestro siguiente capitulo veremos que código va en donde y por qué. Por lo pronto esta es una explicación rápida de como organizar nuestro código y proyecto con Clean Architecture.&lt;/p&gt;

&lt;p&gt;Gracias por leerme y cualquier duda estoy a la orden en los comentarios. &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>cleanarchitecture</category>
      <category>dart</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Registro 001 — Antes de Escribir Código: La Importancia de Planificar tu Proyecto Flutter</title>
      <dc:creator>JR Saucedo</dc:creator>
      <pubDate>Sat, 03 Aug 2024 06:12:13 +0000</pubDate>
      <link>https://dev.to/betoflakes/registro-001-antes-de-escribir-codigo-la-importancia-de-planificar-tu-proyecto-flutter-3p47</link>
      <guid>https://dev.to/betoflakes/registro-001-antes-de-escribir-codigo-la-importancia-de-planificar-tu-proyecto-flutter-3p47</guid>
      <description>&lt;h3&gt;
  
  
  Plan de Trabajo
&lt;/h3&gt;

&lt;p&gt;Bueno, estamos de vuelta con nuestro proyecto y no, aún no empezaremos con el código. Esto me gustaría compartirlo también como un consejo para todos esos nuevos programadores en camino a transformarse en desarrolladores: antes de empezar a escribir cualquier línea de código o bien antes del comando para iniciar su proyecto, hay que tomar una pausa y planear.&lt;/p&gt;

&lt;p&gt;Recuerdo bien cuántos proyectos quise empezar con solo una idea y comenzar a escribir código. Pensando en la marcha, íbamos viendo qué utilizaríamos o cómo lo haríamos, y ahí quedaba ese proyecto, porque como no me tomé el tiempo de planearlo o pensarlo, se quedaba en una idea.&lt;/p&gt;

&lt;p&gt;Por eso mismo, y con el ímpetu de mejorar en nuestro crecimiento como desarrolladores, creo que es momento de platicar de qué irá nuestro proyecto o al menos cómo funcionará. Desde ver qué tecnologías utilizaremos, cómo organizaremos nuestro proyecto y cómo lograremos cumplir con nuestro cometido.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tecnologías
&lt;/h3&gt;

&lt;p&gt;Como ya habíamos platicado en nuestro artículo anterior &lt;a href="https://dev.to/betoflakes/registro-000-listo-para-flutter-sigue-mi-aventura-en-el-desarrollo-de-una-app-con-clean-architecture-3l8g"&gt;Registro 000&lt;/a&gt;, la tecnología principal en nuestro proyecto será Flutter como base de nuestro código. Posteriormente, utilizaremos como base de datos y backend principal Supabase, que, por sus virtudes de transacciones en tiempo real, nos ayudará en la funcionalidad de creación de partidas, sobre todo las públicas (más adelante hablaremos de eso), de fácil publicación y que a los usuarios les llegue de manera efectiva.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estructura y Componentes
&lt;/h3&gt;

&lt;p&gt;Nuestro proyecto se conformará de varias partes esenciales que harán que funcione y cumpla con nuestro propósito. Como se muestra en el diagrama siguiente:&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%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AMFlF2Wkdym2bgIR_dFxc8Q.png" 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%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AMFlF2Wkdym2bgIR_dFxc8Q.png" alt="Diagrama Proytecto"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Data
&lt;/h4&gt;

&lt;p&gt;Nuestra app se conectará al servicio de Supabase, pero antes vamos por partes. Hasta el momento se han detectado tres modelos principales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usuario&lt;/li&gt;
&lt;li&gt;Partida&lt;/li&gt;
&lt;li&gt;Mensaje&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos serán nuestros modelos principales de nuestra capa de datos, los cuales serán los tipos de datos que manejaremos en toda la app. Puede que tengamos otros nuevos, pero como base empezaremos con los anteriormente mencionados.&lt;/p&gt;

&lt;h4&gt;
  
  
  Autenticación
&lt;/h4&gt;

&lt;p&gt;Manejaremos el control de autenticación de usuarios, por lo que inicialmente integraremos las cuentas nativas de los dispositivos, Google y Apple, ya que por defecto, si un usuario está en su dispositivo móvil, tiene una cuenta de cualquiera de estos proveedores. Se está considerando Facebook para ampliar el acceso, por ejemplo, a usuarios de dispositivos no compatibles con ninguno de estos proveedores.&lt;/p&gt;

&lt;p&gt;En el apartado de Supabase, tenemos nuestras tablas, que, si bien se puede observar, empatan con nuestros modelos. Pero igual tenemos unas notas importantes que mencionar sobre algunas de estas tablas:&lt;/p&gt;

&lt;h4&gt;
  
  
  Partidas
&lt;/h4&gt;

&lt;p&gt;Las partidas serán de dos tipos: privadas, entre amigos previamente agregados dentro de la misma plataforma, o públicas, entendiendo que al principio no habrá amigos agregados. La posibilidad de crear partidas públicas ayudará a generar dichas conexiones. Por cuestiones de rendimiento, manejaremos 5 partidas públicas abiertas por usuario. ¿Qué significa abiertas? Nos referimos al estado en el que la partida solo cuenta con el usuario que la creó, esperando un retador.&lt;/p&gt;

&lt;p&gt;Las partidas constarán de un reto estándar de el mejor de 3, o mejor de 5, según la configuración que se elija al realizar el reto. Con esto no generamos partidas de una sola ronda y se genera un poco más de interactividad y competencia.&lt;/p&gt;

&lt;h4&gt;
  
  
  Chat de partida
&lt;/h4&gt;

&lt;p&gt;Durante la partida, la interacción entre los usuarios puede agregar un poco de dinamismo, pero a su vez no queremos crear un ambiente tóxico o abusivo, por lo cual se limitará a emojis. Aunque una partida es básicamente corta (mejor de 3 o 5), se piensa que puede traer un factor social interesante de interacción entre las partidas. Según el impacto que tenga, puede que con ciertos controles de moderación se abra una conversación más allá de emojis.&lt;/p&gt;




&lt;p&gt;Por el momento, creo que ha sido bastante información y se ha estipulado lo suficiente para comenzar, ahora sí, a escribir código. En nuestra siguiente entrega analizaremos y veremos la organización de nuestro proyecto en cuanto a arquitectura y también las librerías o herramientas que utilizaremos para lograr el cometido.&lt;/p&gt;

&lt;p&gt;Gracias por leerme y nos vemos en la siguiente entrega.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Registro 000 - ¿Listo para Flutter? Sigue Mi Aventura en el Desarrollo de una App con Clean Architecture</title>
      <dc:creator>JR Saucedo</dc:creator>
      <pubDate>Sat, 20 Jul 2024 23:53:36 +0000</pubDate>
      <link>https://dev.to/betoflakes/registro-000-listo-para-flutter-sigue-mi-aventura-en-el-desarrollo-de-una-app-con-clean-architecture-3l8g</link>
      <guid>https://dev.to/betoflakes/registro-000-listo-para-flutter-sigue-mi-aventura-en-el-desarrollo-de-una-app-con-clean-architecture-3l8g</guid>
      <description>&lt;h3&gt;
  
  
  Antecedentes
&lt;/h3&gt;

&lt;p&gt;Esta idea surgió con el propósito de cubrir los temas de un curso universitario que impartí un año antes de la pandemia. El objetivo era enseñar a los estudiantes de Diseño Multimedia lo que podían hacer con los conocimientos adquiridos durante los siete semestres previos. Considerando que ya habían tomado cursos de programación, desarrollo de videojuegos y desarrollo web, se desarrolló este pequeño juego para que pudieran ver cómo desarrollar futuras ideas. En su momento, utilizamos tecnologías web(VueJS) y servicios como Firebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Motivación
&lt;/h3&gt;

&lt;p&gt;La curiosidad por aprender y aplicar buenas prácticas en el desarrollo de aplicaciones con Flutter, BLoC y Clean Architecture me ha llevado a iniciar este proyecto. Desarrollaré una aplicación basada en el clásico juego de Piedra, Papel, Tijeras, cumpliendo con las directrices principales: que sea rápida, casi en tiempo real, y con la posibilidad de jugar con amigos. Quiero explorar cómo estas metodologías pueden mejorar la eficiencia y calidad del desarrollo de aplicaciones, además de crear algo divertido y funcional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Propósito
&lt;/h3&gt;

&lt;p&gt;Después de varios años desarrollando en Flutter, mi propósito es aplicar mis conocimientos y compartirlos con la comunidad hispanohablante. Quiero difundir el conocimiento en nuestra lengua materna. No sé si es una crisis de la edad (34 años cuando escribo esto) o simplemente ego, pero me interesa contribuir significativamente a la comunidad que me ha dado tanto, ofreciendo recursos de aprendizaje y más. Como desarrollador senior, mi objetivo es retribuir y enriquecer la comunidad de desarrolladores en español.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plan de Trabajo
&lt;/h3&gt;

&lt;p&gt;Este plan está pensado para desarrollarse en dos partes:&lt;/p&gt;

&lt;h4&gt;
  
  
  Parte 1: Registro público y educación
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Llevaré un registro público de mi avance a través de este blog (me disculpo por adelantado, ya que es la primera vez que lo hago).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Grabación y publicación de una serie de videos donde explicaré de la mejor manera posible las buenas prácticas en el uso de Flutter, BLoC y Clean Architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En esta parte se concentrará mi contribución a la comunidad de desarrollo, compartiendo conocimientos y recursos útiles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Parte 2: Desarrollo privado y lanzamiento
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Esta parte del proyecto será llevada de manera privada y no estará completamente relacionada con el propósito educativo de la iniciativa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El objetivo secundario es publicar e implementar la aplicación final.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aunque no sabemos si la aplicación tendrá éxito, me reservaré esta parte del proceso. Sin embargo, pretendo compartir los resultados de la publicación, tanto negativos como positivos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;La idea es abrir una conversación con la comunidad tecnológica sobre los aprendizajes obtenidos.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bueno entonces sin más, comencemos la pre pre planeación. Agradezco a quien se haya tomado el tiempo de leer.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>spanish</category>
      <category>latam</category>
    </item>
  </channel>
</rss>
