<?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: Armando Picón</title>
    <description>The latest articles on Forem by Armando Picón (@devpicon).</description>
    <link>https://forem.com/devpicon</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%2F46512%2F896b8426-d0aa-4c3a-8a68-46c9bbc6a2c4.jpg</url>
      <title>Forem: Armando Picón</title>
      <link>https://forem.com/devpicon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devpicon"/>
    <language>en</language>
    <item>
      <title>[iOS] CocoaPods cheatsheet</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Fri, 06 Feb 2026 02:37:51 +0000</pubDate>
      <link>https://forem.com/devpicon/ios-cocoapods-cheatsheet-3j5b</link>
      <guid>https://forem.com/devpicon/ios-cocoapods-cheatsheet-3j5b</guid>
      <description>&lt;p&gt;This post is just a reminder about how to use CocoaPods.&lt;/p&gt;

&lt;p&gt;First things first...&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CocoaPods
&lt;/h2&gt;

&lt;p&gt;CocoaPods is a dependency manager for iOS projects.&lt;br&gt;
It integrates third-party libraries into Xcode projects using a &lt;strong&gt;Podfile&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Install ruby
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install ruby
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Install CocoaPods
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo gem install cocoapods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Verify the installation using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialize CocoaPods in a project
&lt;/h2&gt;

&lt;p&gt;First, go to the project folder (where .xcodeproj is located) and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A minimal example of configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;platform :ios, '15.0'

target 'YourAppTarget' do
  use_frameworks!

  pod 'Alamofire'
  pod 'SnapKit'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key things:&lt;br&gt;
    • platform → minimum iOS version&lt;br&gt;
    • target → must match your app target name exactly&lt;br&gt;
    • use_frameworks! → required for many Swift pods&lt;/p&gt;
&lt;h2&gt;
  
  
  Install the dependency
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates:&lt;br&gt;
    • Pods/ folder&lt;br&gt;
    • YourProject.xcworkspace&lt;/p&gt;

&lt;p&gt;🚨 From now on, open the .xcworkspace, not the .xcodeproj.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using a pod in code
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Alamofire

AF.request("https://example.com").response { response in
  print(response)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If it compiles → done.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common commands
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod install     # install dependencies
pod update      # update dependencies
pod repo update # update specs repo
pod deintegrate # remove CocoaPods completely
pod search NAME # search pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Typical problems &amp;amp; fixes
&lt;/h2&gt;

&lt;p&gt;❌ “No such module”&lt;br&gt;
    • You opened .xcodeproj instead of .xcworkspace&lt;br&gt;
    • Target name mismatch in Podfile&lt;/p&gt;

&lt;p&gt;❌ Build settings conflicts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod deintegrate
pod install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Slow installs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod install --repo-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some additional notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CocoaPods is mostly for legacy projects&lt;/li&gt;
&lt;li&gt;For libraries that don't support SPM (Swift Package Manager)&lt;/li&gt;
&lt;li&gt;Consider using only Swift Package Manager&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>cheatsheet</category>
      <category>dependencymanagement</category>
    </item>
    <item>
      <title>Android - Scalable dependency management with version catalogs</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Wed, 13 Dec 2023 21:56:58 +0000</pubDate>
      <link>https://forem.com/devpicon/scalable-dependency-management-with-version-catalog-47lj</link>
      <guid>https://forem.com/devpicon/scalable-dependency-management-with-version-catalog-47lj</guid>
      <description>&lt;p&gt;I’m revisiting some helpful content for starting a new Android project. One of the pain points is how to handle a ton of dependency declarations for multi-module projects. Here is where version catalogs come to our rescue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Declaring dependencies
&lt;/h1&gt;

&lt;p&gt;Before discussing the version catalogs, we will see how dependencies are being declared in an Android project. To declare a dependency in an Android project, you would add something like the following code in your &lt;code&gt;build.gradle.kts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;android&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Here is where the dependencies are declared&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"androidx.core:core-ktx:1.12.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other dependecies&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Coordinates
&lt;/h2&gt;

&lt;p&gt;One important concept to have in mind is the concept of &lt;strong&gt;&lt;em&gt;coordinates&lt;/em&gt;&lt;/strong&gt;. Each coordinate is composed by “&lt;strong&gt;[group]:[artifact name]:[version&lt;/strong&gt;]”. For example, in the example above the coordinate of the &lt;code&gt;core-ktx&lt;/code&gt; dependency is &lt;code&gt;[androidx.core]:[core-ktx]:[1.12.0]&lt;/code&gt;, so the same dependency can be decomposed in a declaration like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"core-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.12.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind this concept; we will return to it later.&lt;/p&gt;

&lt;h2&gt;
  
  
  A common issue with multi-module projects
&lt;/h2&gt;

&lt;p&gt;In case you have more than one module in your project, each dependency needs to be declared on every module that requires the specific dependency. The problem arises with this approach because of having repetitive declarations; every time you want to update a dependency version, you have to make the change in every gradle file where the dependency is declared. This makes dependency handling redundant and messy.&lt;/p&gt;

&lt;p&gt;Here is where &lt;strong&gt;Version catalogs&lt;/strong&gt; come to our rescue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Version catalogs
&lt;/h1&gt;

&lt;p&gt;Version catalogs is a feature of Gradle, so you can use it if you use Gradle as your build system in your Android project. This allows you to declare and organize all your dependencies in a single file, which acts as a catalog where each dependency is associated to a single alias, making this catalogs acts as a source of truth and it can be referenced in every gradle file.&lt;/p&gt;

&lt;p&gt;To enable this option you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new file into the &lt;code&gt;gradle&lt;/code&gt; folder at the project level with the name &lt;code&gt;libs.versions.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Declare the dependencies into that file.&lt;/li&gt;
&lt;li&gt;Reference these declarations in every gradle file of each module.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you don't know where the gradle folder is, you can typically find it at the root project level; you can use the Project view to look at it.&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%2Fje05000htzcgzulteiwa.jpeg" 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%2Fje05000htzcgzulteiwa.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you can ask… how these declarations must be made into that file?&lt;/p&gt;

&lt;h1&gt;
  
  
  Basic usage
&lt;/h1&gt;

&lt;p&gt;Now, let's see the structure of the &lt;code&gt;libs.versions.toml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[versions]&lt;/span&gt;
&lt;span class="py"&gt;core-ktx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.12.0"&lt;/span&gt;

&lt;span class="nn"&gt;[libraries]&lt;/span&gt;
&lt;span class="py"&gt;androidx-core-ktx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"core-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"core-ktx"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the most basic format you have to declare two sections &lt;code&gt;[versions]&lt;/code&gt; and &lt;code&gt;[libraries]&lt;/code&gt;, the first one is used to declare versions for each dependency, the second is for the dependencies itself.&lt;/p&gt;

&lt;p&gt;For this example, we took the same dependency that it has been declared in the first example of this article, in the gradle file. In order to make the &lt;code&gt;core-ktx&lt;/code&gt; dependency available into the libs catalog, we associate the alias &lt;code&gt;androidx-core-ktx&lt;/code&gt; to the GAV (group, artifact, version) coordinates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The main benefit is these declarations are visible by all the modules in your project. So you can reference these declarations from your gradle file.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;android&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Here is where the dependencies are declared&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;androidx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ktx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ...other dependecies&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Every time you added a new declaration in the TOML file you have to sync the project to make it available for the modules.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also, using Version catalogs let you to reference the same version for multiple different libraries, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[versions]&lt;/span&gt;
&lt;span class="py"&gt;android-paging&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3.2.1"&lt;/span&gt;

&lt;span class="nn"&gt;[libraries]&lt;/span&gt;
&lt;span class="py"&gt;android-paging-common&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.paging:paging-common-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android-paging"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;android-paging-runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.paging:paging-runtime-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android-paging"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;android-paging-rxjava2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.paging:paging-rxjava2-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android-paging"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we simplify the coordinates using the module to group the &lt;code&gt;[group]:[artifact]&lt;/code&gt; pair and use the same version reference for all the android-paging dependencies.&lt;/p&gt;

&lt;h1&gt;
  
  
  Going a bit further
&lt;/h1&gt;

&lt;p&gt;Not only you can declare the regular dependencies in that TOML file, you can declare your plugins and even create bundles for grouping dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to declare plugins
&lt;/h2&gt;

&lt;p&gt;To declare a plugin you only need to add the &lt;code&gt;[plugins]&lt;/code&gt; section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[versions]&lt;/span&gt;
&lt;span class="err"&gt;//Here&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;versions&lt;/span&gt; &lt;span class="err"&gt;are&lt;/span&gt; &lt;span class="err"&gt;declared&lt;/span&gt;
&lt;span class="py"&gt;android-gradle-plugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"8.2.0"&lt;/span&gt;

&lt;span class="nn"&gt;[libraries]&lt;/span&gt;
&lt;span class="err"&gt;//Here&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;libraries&lt;/span&gt; &lt;span class="err"&gt;are&lt;/span&gt; &lt;span class="err"&gt;declared&lt;/span&gt;

&lt;span class="nn"&gt;[plugins]&lt;/span&gt;
&lt;span class="py"&gt;android-application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.android.application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android-gradle-plugin"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, after syncing the project, we can change the references from this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Top-level build file where you can add configuration options common to all sub-projects/modules.&lt;/span&gt;
&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.android.application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"8.2.0"&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="c1"&gt;//... more plugins are placed here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Top-level build file where you can add configuration options common to all sub-projects/modules.&lt;/span&gt;
&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="c1"&gt;//... more plugins are placed here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to create your own bundle
&lt;/h2&gt;

&lt;p&gt;To create a bundle, you have to add a &lt;code&gt;[bundles]&lt;/code&gt; section into your TOML file. For example, here I’m adding the Room bundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[versions]&lt;/span&gt;
&lt;span class="py"&gt;room&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2.6.1"&lt;/span&gt;
&lt;span class="py"&gt;ksp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.9.0-1.0.13"&lt;/span&gt;

&lt;span class="nn"&gt;[libraries]&lt;/span&gt;
&lt;span class="py"&gt;androidx-room-compiler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.room"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room-compiler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;androidx-room-ktx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.room"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;androidx-room-runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;group&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"androidx.room"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room-runtime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"room"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nn"&gt;[plugins]&lt;/span&gt;
&lt;span class="py"&gt;kotlin-symbol-processing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.google.devtools.ksp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;version.ref&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ksp"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nn"&gt;[bundles]&lt;/span&gt;
&lt;span class="py"&gt;android-room-bundle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"androidx-room-ktx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"androidx-room-runtime"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, you can use the bundle like this after syncing your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// More plugins are added here...&lt;/span&gt;
        &lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;android&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Some dependencies are declared here&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bundles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;ksp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;androidx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compiler&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;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;It’s also worth mentioning that using a version catalog is likely the best way to establish a single source of truth for all your project dependencies. It's also worth mentioning that the official documentation has a section about this topic.&lt;/p&gt;

&lt;p&gt;You can experiment with different strategies using bundles to organize the necessary dependencies for each project, avoiding the tedious process of checking each Gradle file to see what you’ve declared.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Migrate to version catalogs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/build/migrate-to-catalogs" rel="noopener noreferrer"&gt;https://developer.android.com/build/migrate-to-catalogs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sharing dependency version between projects&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.gradle.org/current/userguide/platforms.html" rel="noopener noreferrer"&gt;https://docs.gradle.org/current/userguide/platforms.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>dependencymanagement</category>
      <category>gradle</category>
      <category>versioncatalogs</category>
    </item>
    <item>
      <title>Android - Desmitificando Clean Architecture</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Thu, 30 Dec 2021 17:22:28 +0000</pubDate>
      <link>https://forem.com/devpicon/android-desmitificando-clean-architecture-33m6</link>
      <guid>https://forem.com/devpicon/android-desmitificando-clean-architecture-33m6</guid>
      <description>&lt;h2&gt;
  
  
  Antes de comenzar…
&lt;/h2&gt;

&lt;p&gt;Si es tu primera vez leyendo sobre Clean Architecture quizá te convenga saber algunas cosillas antes de seguir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean Architecture es el título de un libro escrito por Robert C. Martin (aka. Uncle Bob)&lt;/li&gt;
&lt;li&gt;No es una arquitectura en sí, sino una guía que encierra un conjunto de principios a seguir.&lt;/li&gt;
&lt;li&gt;La base de esta guía se encuentra en aplicar los principios SOLID.&lt;/li&gt;
&lt;li&gt;En términos generales, te intenta llevar a una estructura basada en el Dominio (&lt;em&gt;Domain&lt;/em&gt;) como punto central de tu aplicación (la capa en la que se implementará la lógica de tu aplicación). ¿Alguien habló de Domain-driven development?&lt;/li&gt;
&lt;li&gt;Un buen número de desarrolladores la confunde la arquitectura con N-capas.&lt;/li&gt;
&lt;li&gt;No es el santo grial, es una expresión algo mainstream entre los desarrolladores y por ende sirve como una forma fácil de describirle a un desarrollador de qué manera se ha estructurado un proyecto.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Qué es una arquitectura?
&lt;/h2&gt;

&lt;p&gt;Básicamente, es una estructura, una manera de distribuir los componentes que conforman una aplicación en distintas agrupaciones. Por esto mismo, no existe una única manera de organizar tu proyecto. Diversos aspectos como el estado de tu proyecto, el tamaño de tu equipo, el tiempo, etc influirán en las decisiones que tomes al momento de decidir la manera en la que organizarás los componentes de tu aplicación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean Architecture en el mundo Android
&lt;/h2&gt;

&lt;p&gt;Mucho se ha dicho y escrito sobre cómo aplicar &lt;em&gt;Clean Architecture&lt;/em&gt; en las aplicaciones que desarrollamos, un buen número de desarrolladores te hablarán sobre &lt;em&gt;Separation of concerns and testing&lt;/em&gt; como las principales características de seguir estos principios, suelen a su vez olvidar un aspecto muy importante sobre &lt;em&gt;Clean Architecture&lt;/em&gt; y que consiste en que su base yace en la implementación de la capa de Dominio.&lt;/p&gt;

&lt;p&gt;Dicho esto ¿cómo se estructuraría un proyecto base siguiendo estos principios? Para trabajar en esto es importante establecer dos consideraciones importantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existe una regla en &lt;em&gt;Clean Architecture&lt;/em&gt; por la cual toda capa exterior dependerá de una capa interior (y no al revés), quedando para el final la capa de Dominio sin dependencia alguna.&lt;/li&gt;
&lt;/ul&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%2Fdadpc22gfbugpf3pmd17.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdadpc22gfbugpf3pmd17.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existe un flujo de datos que pasa por todas las capas externas e internas tanto de ida desde que se efectúe el ingreso de datos por parte del usuario (o de los sensores), pasando por la lógica de negocio/aplicación y terminando en la persistencia de los datos o el envío de los mismos a un servicio remoto, como también de vuelta con el resultado de la operación con el servicio hasta la presentación del resultado a nuestro usuario.&lt;/li&gt;
&lt;/ul&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%2Fccepm0me3tm77wsfltwp.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccepm0me3tm77wsfltwp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Teniendo en cuenta estos dos aspectos, para una estructura básica contaríamos con tres módulos: &lt;em&gt;presentation&lt;/em&gt;, &lt;em&gt;domain&lt;/em&gt; y &lt;em&gt;data&lt;/em&gt;. La relación entre estos sería de la siguiente manera:&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%2F96jyttwblu32zd88ru05.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96jyttwblu32zd88ru05.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué componentes irían en cada capa?
&lt;/h2&gt;

&lt;p&gt;Es importante reiterar que al hablar de arquitectura, hablamos de organización y estructura, por lo tanto, la distribución y qué componentes en específico irán en cada módulo dependerá del patrón que decidas emplear y el propósito de cada módulo: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Domain&lt;/em&gt; deberá contener los elementos que contengan la lógica de tu aplicación y la lógica del negocio. Con ello en mente, tendremos clases de dominio, y además componentes que tendrán la lógica como son los Casos de Uso o Interactors. Este módulo NO debe depender del Android framework ni de dependencias de terceros. Este módulo puede ser un módulo Kotlin.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Presentation&lt;/em&gt; tendrá los elementos que permitan mostrar información a nuestro usuario, recibir datos del mismo o de sensores. Además de los componentes visuales propios de Android (Activity y Fragment) y su sistema de UI (archivos XML o funciones de Compose), si se siguen patrones como MVP o MVVM, tendremos también Presenters o ViewModels respectivamente. Este módulo es un módulo Android.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Data&lt;/em&gt; va a incluir todas las dependencias de networking (Retrofit, volley, etc) y de persistencia de datos (Room, SharedPreferences, DataStore, Firebase, etc). Si se emplea el patrón repositorio será en esta capa en la que tendremos la implementación de los repositorios y las fuentes de datos (data sources). Este módulo es un módulo Android también.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguramente aquí te podría surgir la siguiente duda: si &lt;em&gt;Domain&lt;/em&gt; no tiene visibilidad de &lt;em&gt;Data&lt;/em&gt; ¿cómo es que podríamos inyectar los repositorios en nuestros casos de uso? La respuesta se encuentra en el principio de Inversión de Dependencia (&lt;em&gt;Dependency inversion&lt;/em&gt;) de SOLID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency inversion principle
&lt;/h2&gt;

&lt;p&gt;Este principio de SOLID establece dos consignas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Los módulos de alto nivel no deberían importar nada de un módulo de bajo nivel. Pero ambos deberían depender de abstracciones (interfaces).&lt;/li&gt;
&lt;li&gt;Las abstracciones no deberían depender de los detalles. Los detalles (las implementaciones concretas) deberían depender de las abstracciones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Teniendo en mente esto, nuestro módulo &lt;em&gt;Domain&lt;/em&gt; deberá ser propietario de la interfaz del repositorio que se implementará dentro del módulo &lt;em&gt;Data&lt;/em&gt;. &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%2Fgboebcmfhsy7uuprzhjg.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgboebcmfhsy7uuprzhjg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En código esto luciría más o menos de la siguiente manera, en el módulo &lt;em&gt;Domain&lt;/em&gt; estaría la abstracción de un BookRepository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface BookRepository {
    suspend fun getBooks():List&amp;lt;Book&amp;gt;
}
class GetBooksUseCase(
    private val bookRepository: BookRepository
) { /*...*/ }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mientras que en el módulo Data iría su implementación.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class BookRepositoryImpl (...) : BookRepository {
    override suspend fun getBooks(): List&amp;lt;Book&amp;gt; { /* ... */}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De este modo al momento de crear una instancia de nuestro caso de uso le podremos inyectar la implementación debido a la interfaz que hemos declarado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Podría mencionar algunas cosas como parte de la conclusión:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contar con una arquitectura o forma de organizar los componentes es mejor que no tener ninguna.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Clean Architecture&lt;/em&gt; no es una arquitectura en sí, pero nos provee de una guía a seguir para estructurar nuestros proyectos.&lt;/li&gt;
&lt;li&gt;Existen otras arquitecturas que no cuentan con mucha fama, pero no por ello son menos útiles.&lt;/li&gt;
&lt;li&gt;Teniendo esta estructura, puedes usar lo que se te antoje tanto en la presentación (sea Views-XMLs o Compose) como a nivel del acceso a datos (Retrofit, Room, SharedPreferences, etc).&lt;/li&gt;
&lt;li&gt;En mi experiencia, la buena aplicación de los principios SOLID te da una buena base para ir perfilando la arquitectura de tu proyecto.&lt;/li&gt;
&lt;li&gt;La relanzada &lt;a href="https://developer.android.com/jetpack/guide" rel="noopener noreferrer"&gt;guía oficial de arquitectura de Android&lt;/a&gt; no sigue Clean Architecture, pero sí provee de una arquitectura separada en capas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164" rel="noopener noreferrer"&gt;Clean Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle" rel="noopener noreferrer"&gt;Dependency Inversion principle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fernandocejas.com/blog/engineering/2019-05-08-architecting-android-reloaded/" rel="noopener noreferrer"&gt;Architecting Android…Reloaded by Fernando Cejas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>programming</category>
      <category>architecture</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Kotlin - Scope Functions (let, with, run, apply &amp; also)</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 22 Feb 2021 00:36:49 +0000</pubDate>
      <link>https://forem.com/devpicon/kotlin-scoped-functions-let-with-run-apply-also-dhp</link>
      <guid>https://forem.com/devpicon/kotlin-scoped-functions-let-with-run-apply-also-dhp</guid>
      <description>&lt;p&gt;Empecemos viendo este código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  name?.let{
    //...
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estoy seguro que en algún momento lo has visto y sabes que es una forma de validar que &lt;code&gt;name&lt;/code&gt; no sea nulo antes de emplear el valor dentro del bloque de código dentro de la función &lt;code&gt;let&lt;/code&gt;. Pero ¿realmente sabes las implicancias del uso de dicha función? Si la respuesta es no, pues esta publicación es para ti.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definiendo las &lt;em&gt;scope functions&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Según la &lt;a href="https://kotlinlang.org/docs/scope-functions.html"&gt;documentación oficial&lt;/a&gt; son funciones cuyo único propósito es "ejecutar un bloque de código dentro del contexto de un objeto". Creo que la explicación es algo sencilla, básicamente es una forma de organizar nuestro código y hacerlo mejor leíble.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué &lt;em&gt;scope functions&lt;/em&gt; trae Kotlin?
&lt;/h2&gt;

&lt;p&gt;Básicamente tenemos 5 &lt;em&gt;scope functions&lt;/em&gt;: &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;apply&lt;/code&gt; y &lt;code&gt;also&lt;/code&gt;; adicionalmente hay 2 funciones extras &lt;code&gt;takeIf&lt;/code&gt; y &lt;code&gt;takeUnless&lt;/code&gt; que nos permitirán adicionar algunas validaciones de estado en medio de una cadena de invocación (o en tras palabras cuando concatenas varias &lt;em&gt;scope functions&lt;/em&gt;) y que suelen emplearse junto con las 5 anteriores.&lt;/p&gt;

&lt;p&gt;Como la documentación lo señala hay dos elementos que distinguen a una &lt;em&gt;scope function&lt;/em&gt; de otra:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;la forma en que se referencia al objeto de contexto&lt;/li&gt;
&lt;li&gt;el valor de retorno&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Por la forma en que se referencia al objeto de contexto
&lt;/h3&gt;

&lt;p&gt;La razón por la que tenemos un &lt;code&gt;it&lt;/code&gt; o un &lt;code&gt;this&lt;/code&gt; es para simplificar o acortar el nombre de la variable original y,  básicamente, te dirá si el objeto va a recibir la lambda (para el caso del &lt;code&gt;this&lt;/code&gt;) o si el objeto va a pasarse como argumento de la lambda (para el caso de &lt;code&gt;it&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Entonces, ¿en qué casos el objeto de contexto va a recibir la lambda? &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt; y &lt;code&gt;apply&lt;/code&gt; y ¿en qué casos el objeto de contexto se pasará como argumento? &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;also&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por el valor de retorno
&lt;/h3&gt;

&lt;p&gt;Para esta situación tendremos el retorno del mismo objeto de contexto para el caso de &lt;code&gt;apply&lt;/code&gt; y &lt;code&gt;also&lt;/code&gt; o el valor de resultado de la lambda en el caso de &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt; y &lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué función elegir?
&lt;/h2&gt;

&lt;p&gt;Teniendo estas dos distinciones en mente, &lt;a href="https://kotlinlang.org/docs/scope-functions.html#functions"&gt;la documentación oficial detalla cada una de las funciones&lt;/a&gt; y los posibles escenarios de uso. De esa misma documentación saqué este cuadro que ayuda mucho a resumir lo dicho anteriormente:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Función&lt;/th&gt;
&lt;th&gt;Referencia de objeto&lt;/th&gt;
&lt;th&gt;Valor de retorno&lt;/th&gt;
&lt;th&gt;¿Es una &lt;em&gt;extension function&lt;/em&gt;?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;let&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;it&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resultado de la lambda&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;this&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resultado de la lambda&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Resultado de la lambda&lt;/td&gt;
&lt;td&gt;No, cuando se llama sin el objeto de contexto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;with&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;this&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resultado de la lambda&lt;/td&gt;
&lt;td&gt;No, porque toma el objeto de contexto como argumento&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apply&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;this&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Objeto de contexto&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;also&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;it&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Objeto de contexto&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;También la documentación brinda una pequeña guía de referencia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ejecución de una lambda en objetos non-null: &lt;code&gt;let&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Introducir una expresión como una variable en un ámbito local: &lt;code&gt;let&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configuración de un objeto: &lt;code&gt;apply&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configuración de un objeto y computación del resultado: &lt;code&gt;run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ejecutar sentencias donde una expresión es requerida: &lt;code&gt;run&lt;/code&gt; a secas sin objeto de contexto ni como función extendida&lt;/li&gt;
&lt;li&gt;Efectos adicionales: &lt;code&gt;also&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Agrupar llamadas a funciones en un objeto: &lt;code&gt;with&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  takeIf y takeUnless
&lt;/h2&gt;

&lt;p&gt;Estas dos funciones que vienen en la biblioteca estandar de Kotlin, no son consideradas &lt;em&gt;scope functions&lt;/em&gt;; sin embargo, se emplean junto con ellas y sirven para realizar algunas validaciones. &lt;/p&gt;

&lt;p&gt;La documentación oficial &lt;a href="https://kotlinlang.org/docs/scope-functions.html#takeif-and-takeunless"&gt;tiene algunos buenos ejemplos&lt;/a&gt; de cómo emplearlas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Me resultan super interesantes las &lt;em&gt;scope functions&lt;/em&gt; y este artículo tiene por intención hacer un breve resumen de en qué consisten y cuando emplearlas. Es importante practicar su uso para acostumbrarse a sus diferencias y casos de uso, dado que por lo similares que son resultado fácil confundirlas y equivocar su uso.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>scopefunction</category>
      <category>spanish</category>
    </item>
    <item>
      <title>¿Qué nos dejó el 2020 y que nos traerá el 2021?</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Fri, 01 Jan 2021 03:36:42 +0000</pubDate>
      <link>https://forem.com/devpicon/que-nos-dejo-el-2020-y-que-nos-traera-el-2021-2kgp</link>
      <guid>https://forem.com/devpicon/que-nos-dejo-el-2020-y-que-nos-traera-el-2021-2kgp</guid>
      <description>&lt;p&gt;Hola amigos y amigas de Codalot Podcast, que año para complicado el que nos tocó pasar, cierto? y quería empezar expresando mis condolencias a todos los que sufrieron de la pérdida de algún ser querido o de alguna persona cercana producto de esta pandemia.&lt;/p&gt;

&lt;p&gt;Si bien es cierto que diversos sectores económicos sufrieron de un gran impacto producto de la crisis que se generó por causa de las medidas que tomó cada gobierno, producto de ello se perdieron muchos puestos de trabajo; sin embargo, dentro de las ocupaciones que no sufrieron tanto durante esta pandemia estuvieron los programadores y los desarrolladores de software.&lt;/p&gt;

&lt;p&gt;Si fuiste uno de estos, puedes sentirte privilegiado y a su vez puedes sentirte feliz de haber tomado la decisión de dedicarte a esto.&lt;/p&gt;

&lt;h2&gt;
  
  
  El año del trabajo remoto
&lt;/h2&gt;

&lt;p&gt;Este año que termina ha sido un año lleno de desafíos y de cambios significativos para cada uno de nosotros. Muy aparte de las cuarentenas y demás restricciones dictaminadas por cada gobierno, fue el año del trabajo remoto o home office.&lt;br&gt;
Un problema latente con el trabajo remoto en este tiempo es que, sumado al hecho de que muchos de nosotros no podíamos salir, puede llegar a ser tedioso y muy agotador. Por eso se torna importante contar con rutinas, generar hábitos, aprender a desconectarse y aprender a ser creativos para no llegar al colapso.&lt;/p&gt;

&lt;p&gt;Sin embargo, para los escépticos del trabajo remoto, ahora ya se tiene evidencia de que esta dinámica bien implementada puede ser no solo beneficiosa sino también altamente productiva. Lo que abriría las puertas para que se armen espacios de trabajo híbridos donde el que quiera pueda ir a una oficina a trabajar y el que no lo desee pueda trabajar desde donde le plazca. Evidentemente, esto dependerá de la forma en que vaya evolucionando la crisis.&lt;/p&gt;

&lt;h2&gt;
  
  
  El mundo Android en el 2020
&lt;/h2&gt;

&lt;p&gt;En el mundo Android, este fue el año de las llamadas habilidades de Desarrollo Moderno en Android o conocido en inglés como “MAD skills”, se ha hecho mucho esfuerzo en la adopción de Kotlin por parte de Android en las diferentes dependencias o bibliotecas que se han venido trabajando. Esto ha permitido potenciar el conjunto de bibliotecas que yacen bajo el nombre de Jetpack y que forman parte de la manera en que Google recomienda la construcción de las nuevas aplicaciones, hecho que nos debe llevar a una necesaria actualización y adopción.&lt;/p&gt;

&lt;p&gt;También, se ha hecho incapié en el uso de App Bundle, una nueva forma de distribución que permite la optimización de los recursos de nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Adicionalmente, han habido mejoras significativas en la construcción de las UIs mediante el uso de componentes como ConstraintLayout 2 y MotionLayout. Los cuales han de estar muy vigentes también durante el próximo año.&lt;/p&gt;

&lt;p&gt;Finalmente, con las nuevas actualizaciones de Android como sistema operativo han llegado nuevas restricciones al acceso a data sensible que debemos tomar en consideración si deseamos mantener nuestras aplicaciones vigentes.&lt;/p&gt;

&lt;p&gt;De hecho, tras el apoyo de Google hace 3 años, hoy en día no cabe duda del valor que Kotlin tiene para nosotros y, de hecho, si no estás familiarizado con dicho lenguaje tus opciones de empleabilidad van a caer dramáticamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Las comunidades se reinventaron
&lt;/h2&gt;

&lt;p&gt;Las comunidades de desarrolladores también se vieron en la necesidad de adaptarse; tuvieron que pasar de organizar eventos de forma presencial con toda la logística que ello conlleva, a organizarlas de manera virtual. Pasaron de buscar espacios físicos a buscar plataformas de streaming que facilitaran la organización de pláticas.&lt;/p&gt;

&lt;p&gt;Lo anterior también llevó a replantearse la necesidad de cobrar por el acceso a los eventos, dado que ya no se cuenta con el atractivo inherente de un evento físico, algunos eventos pasaron a cobrar algo simbólico o simplemente a liberar la entrada.&lt;/p&gt;

&lt;p&gt;Esto también provocó el replanteamiento de las charlas brindadas por los speakers, dado que anteriormente tenía sentido compartir la misma presentación en múltiples lugares con público distinto en cada una y ahora una charla dada en un evento tranquilamente es accesible a través de las grabaciones que podían quedar en Youtube, lo que los lleva a presentar algo nuevo en cada presentación.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué vendrá en el 2021?
&lt;/h2&gt;

&lt;p&gt;Este año que viene será el año de Compose, una nueva forma de construir interfaces de manera declarativa y que viene siendo escrita enteramente en Kotlin, y de Hilt, una dependencia que crea una capa de abstracción sobre Dagger, y que nos permitirá efectuar la inyección de dependencias de una forma más natural. Ambos, van a contar con sus primeros releases estables durante este próximo año.&lt;/p&gt;

&lt;p&gt;No podemos dejar de lado la mención a Kotlin Multiplatform, una solución que permite compartir código durante el desarrollo de aplicaciones multiplataforma y que se ha venido cocinando durante un buen tiempo, ahora mismo se encuentra aún en alpha, pero podríamos ver sus primeros betas en el trascurso de este 2021 también.&lt;/p&gt;

&lt;p&gt;Otro cambio más que se nos viene será la adopción de nuevos nombres código o codenames para las nuevas versiones de Android Studio empezando por la versión 4.3 que además de cambiar el esquema de versionamiento que estará más alineado con lo que se viene haciendo con IntelliJ Idea nos traerá un nuevo nombre código Android Studio Artic Fox.&lt;br&gt;
&lt;a href="https://android-developers.googleblog.com/2020/12/announcing-android-studio-arctic-fox.html"&gt;https://android-developers.googleblog.com/2020/12/announcing-android-studio-arctic-fox.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este nuevo año traerá consigo muchas adaptaciones de lo viejo a lo nuevo; la entera adopción de Kotlin, la adopción de los MAD skills, etc.&lt;br&gt;
&lt;a href="https://developer.android.com/series/mad-skills"&gt;https://developer.android.com/series/mad-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claro está que más allá de las novedades, lo que no cambiará será la necesidad de conocer cosas tan fundamentales como los buenos principios de programación, la adopción de patrones de diseño de software, entre otros conocimientos que nos ayudarán a escribir y estructurar nuestro código de mejor forma, y que a su vez nos llevará a desarrollar mejores aplicaciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cierre
&lt;/h2&gt;

&lt;p&gt;Espero que este nuevo año traiga consigo cosas positivas, que puedan seguir cuidándose a ustedes y a sus familias. Y que podamos seguir creciendo en medio de la adversidad que hoy vivimos. Un abrazo a todos y les deseo un Feliz Año Nuevo 2021.&lt;/p&gt;

&lt;p&gt;Adios!&lt;/p&gt;

</description>
      <category>codalot</category>
      <category>podcast</category>
      <category>android</category>
      <category>community</category>
    </item>
    <item>
      <title>Kotlin Coroutines 101 — Jobs</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Sun, 17 May 2020 18:33:01 +0000</pubDate>
      <link>https://forem.com/devpicon/kotlin-coroutines-101-jobs-1d33</link>
      <guid>https://forem.com/devpicon/kotlin-coroutines-101-jobs-1d33</guid>
      <description>&lt;h3&gt;
  
  
  Kotlin Coroutines 101 — Jobs
&lt;/h3&gt;

&lt;p&gt;En este artículo estaré vamos a mencionar algunos aspectos que encuentro interesantes sobre los Jobs.&lt;/p&gt;

&lt;h4&gt;
  
  
  ¿Qué es un Job?
&lt;/h4&gt;

&lt;p&gt;En el primer artículo que escribí tuvimos ocasión de lanzar una corutina mediante la acción de un botón. Pero ¿qué pasa si por algún motivo queremos verificar el estado de la corutina o cancelarla, si fuera necesario?. Es aquí donde entra a tallar la tarea de un &lt;em&gt;Job&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Un &lt;em&gt;Job&lt;/em&gt; es una representación de una corutina y nos va a permitir realizar algunas acciones sobre ella.&lt;/p&gt;

&lt;h4&gt;
  
  
  ¿Cuáles son sus estados?
&lt;/h4&gt;

&lt;p&gt;Los &lt;em&gt;Jobs&lt;/em&gt; cuentan con estados, los cuales listaré a continuación:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8cJ8VLXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A-s7IzZDbFfZGAdf2NtD1CQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8cJ8VLXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A-s7IzZDbFfZGAdf2NtD1CQ.png" alt="" width="800" height="434"&gt;&lt;/a&gt;Ciclo de vida de un &lt;em&gt;Job&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; : representa el estado de creación de una corutina y la asociación de un &lt;em&gt;Job&lt;/em&gt; a ella.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active&lt;/strong&gt; : este estado representa el momento en el que se inicia ejecución y mantiene la ejecución de una corutina.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completing&lt;/strong&gt; : este estado representa el momento en que la corutina ha finalizado su ejecución y precisa esperar a que otras corutinas asociadas a ella o en una relación de padre-hijo finalicen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completed&lt;/strong&gt; : este estado representa el estado final de una corutina, el momento en el que toda su ejecución, incluyendo las corutinas hijas, ha finalizado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancelling&lt;/strong&gt; : este estado representa el momento en el que se ha cancelado la corutina y se espera la cancelación de los &lt;em&gt;Jobs&lt;/em&gt; asociados a ella.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancelled&lt;/strong&gt; : este es el estado final una vez que se ha procedido a la cancelación total o completa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Debido a la existencia de estos estados, es posible mediante un &lt;em&gt;Job&lt;/em&gt; acceder a las siguientes propiedades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;isActive&lt;/strong&gt; : esta propiedad nos permitirá saber si un &lt;em&gt;Job&lt;/em&gt; se encuentra en estado activo o no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;isCancelled&lt;/strong&gt; : esta propiedad nos permitirá saber si un &lt;em&gt;Job&lt;/em&gt; ha sido cancelado o no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;isCompleted&lt;/strong&gt; : esta propiedad nos permitirá saber si un &lt;em&gt;Job&lt;/em&gt; ha finalizado o ha completado todas sus operaciones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Cuándo emplear estas propiedades? La respuesta sencilla sería emplearlas en momentos en los que la ejecución o lógica de tu corutina demande saber si debe continuar o no si el estado de la misma cambia.&lt;/p&gt;

&lt;h4&gt;
  
  
  La función invokeOnCompletion
&lt;/h4&gt;

&lt;p&gt;Un aspecto interesante de los &lt;em&gt;Jobs&lt;/em&gt; es que es posible ejecutar código una vez que estos finalizan y esto es gracias a la función invokeOnCompletion(), esta función recibe como parámetro un objeto &lt;em&gt;nullable&lt;/em&gt; de tipo Throwable? que nos permitirá validar la causa por la que una corutina fue cancelada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;job1.invokeOnCompletion { throwable -&amp;gt;  
    log("Complete my job 1")
    throwable?.let {  
        log("There is a throwable object!")
        when ( it ) {
            is CancellationException -&amp;gt; {
                log( it.message ?: "Without message")
            }
        }
    }  
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ¿Cómo cancelar un job?
&lt;/h4&gt;

&lt;p&gt;Cancelar un &lt;em&gt;Job&lt;/em&gt; se puede conseguir mediante la invocación de su función cancel(). Sin embargo, te va a pedir que pases una instancia de la clase CancellationException, preferiblemente hay que agregarle un mensaje que indique la causa por la que se está cancelando el &lt;em&gt;Job&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  ¿Cómo concatenar jobs?
&lt;/h4&gt;

&lt;p&gt;Concatenar &lt;em&gt;Jobs&lt;/em&gt; es relativamente sencillo, para ello requerimos ejecutar la función join(). El comportamiento por defecto de la función join() implica que la corutina que lo invoque se suspenda hasta que este &lt;em&gt;Job&lt;/em&gt; esté completo. Sin embargo, si al builder de turno le pasamos el parámetro start=CoroutineStart.LAZY lo que acontecerá es que dicho &lt;em&gt;Job&lt;/em&gt; pasará a un estado activo en el punto en el que join() sea invocado.&lt;/p&gt;

&lt;h4&gt;
  
  
  ¿Cómo definir una relación de padre/hijo entre Jobs?
&lt;/h4&gt;

&lt;p&gt;Definir una relación de padre e hijos es posible si pasas el &lt;em&gt;Job&lt;/em&gt; como parte del contexto de la corutina que quieres definir como &lt;em&gt;Job&lt;/em&gt; hijo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val job1 = coroutineScope.launch(start = CoroutineStart.LAZY, 
                                 context = handlerException) {...}

val childCoroutineScope = CoroutineScope(Dispatchers.Main + job1)
val job2 = childCoroutineScope.launch{...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ¿Cómo manejar una excepción en un job?
&lt;/h4&gt;

&lt;p&gt;Para manejar excepciones tienes dos forma; la primera, de forma tradicional usando un try/catch en la sección de código que quieres asegurar; la otra, es declarando una instancia de CoroutineExceptionHandler, el cual recibe como parámetros tanto un objeto conteniendo información sobre el contexto de la corutina y un objeto del tipo Throwable. Este objeto debe pasarse como parte del contexto de la corutina.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val handlerException = CoroutineExceptionHandler {
    coroutineContext, throwable -&amp;gt;  
        run {  
                log("$coroutineContext - ${throwable.message}")
        }  
}  

val job1 = coroutineScope.launch(context = handlerException ) {...}  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para complementar les dejo un video para complementar el contenido de este artículo, regálenme un Me gusta si les es de utilidad y un comentario en el video.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/T3cj6NGU4w0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




</description>
      <category>android</category>
      <category>coroutine</category>
      <category>programación</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Kotlin Coroutines on Android 101</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 27 Apr 2020 06:25:32 +0000</pubDate>
      <link>https://forem.com/devpicon/kotlin-coroutines-on-android-101-1ij</link>
      <guid>https://forem.com/devpicon/kotlin-coroutines-on-android-101-1ij</guid>
      <description>&lt;p&gt;Las corutinas son una de las características que gracias a Kotlin tenemos hoy en día y que busca simplificar la forma en la que se ejecutan tareas  asíncronas. Este artículo tiene por objetivo hacer un repaso por los conceptos claves para entender cómo funciona.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Las corutinas actúan de forma similar; sin embargo, es importante recalcar que no son hilos.&lt;/li&gt;
&lt;li&gt;Varias corutinas pueden ser ejecutadas en un mismo hilo.&lt;/li&gt;
&lt;li&gt;Internamente se hace uso de un pool de hilos que nos proveerá el sistema.&lt;/li&gt;
&lt;li&gt;Las funciones suspendidas o &lt;em&gt;suspend functions&lt;/em&gt; es una variante de nuestras funciones regulares pero que pueden ser pausadas y resumidas en un momento posterior.&lt;/li&gt;
&lt;li&gt;Para la ejecución de corutinas o funciones suspendidas es necesario establecer previamente el ámbito o &lt;em&gt;scope&lt;/em&gt; en el que van a ser ejecutados (Ej. CoroutineScope)&lt;/li&gt;
&lt;li&gt;Además del ámbito, la ejecución de una corutina necesita un punto de entrada que se establece mediante el uso de un &lt;em&gt;coroutine builder&lt;/em&gt; (Ej. &lt;code&gt;launch{}&lt;/code&gt; o &lt;code&gt;async{}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Para establecer en qué conjunto de hilo o hilos se ejecutarán nuestras corutinas y funciones suspendidas se dispone de los &lt;code&gt;Dispatchers&lt;/code&gt; (&lt;code&gt;Main&lt;/code&gt;, &lt;code&gt;IO&lt;/code&gt; y &lt;code&gt;Default&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Las funciones suspendidas solo pueden ejecutarse dentro de una corutina o desde otra función suspendida.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No te preocupes si por el momento todo lo que he señalado hasta aquí se lee como chino; vamos a ejemplificar estos puntos e irlos explicando poco a poco.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agregar dependencias
&lt;/h2&gt;

&lt;p&gt;Como primer paso para entrar al mundo de las corutinas debemos agregar las siguientes dependencias a nuestro proyecto. Toma en consideración que a la fecha de publicación de este artículo la versión existente es la &lt;code&gt;1.3.4&lt;/code&gt;, tal vez para cuando tú leas este artículo esta versión haya cambiado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    def coroutines_version = "1.3.4"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Crear layout
&lt;/h2&gt;

&lt;p&gt;Para centrarnos en probar las corutinas vamos a crear una interfaz sencilla que contenga un elemento de tipo &lt;code&gt;Button&lt;/code&gt; con el id &lt;code&gt;@+id/button_launch&lt;/code&gt; y un elemento &lt;code&gt;TextView&lt;/code&gt; con el id &lt;code&gt;@+id/text_result&lt;/code&gt;. ¿Cómo se deben distribuir en la pantalla? Es algo que dejaré a tu criterio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparar nuestras funciones base
&lt;/h2&gt;

&lt;p&gt;Antes de tocar las corutinas necesitaremos crear algunas funciones utilitarias como las que muestro a continuación. Las puedes agregar a tu implementación de tu clase &lt;code&gt;MainActivity.kt&lt;/code&gt; (asumiendo que no le cambiaste el nombre por defecto al momento de crear tu &lt;em&gt;Activity&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun showResult (result: String){
    // Aquí vamos a aprovechar el uso de los synthetic imports para obtener
    // la referencia al textview que agregamos en nuestro UI directamente
    text_result.text = text_result.text.toString() + result + "\n"
}

fun log (message: String){
    // Emplearemos esta función para ayudarnos a identificar el hilo en el 
    // que se está ejecutando nuestra corutina. No siempre será el mismo hilo.
    println("[${Thread.currentThread().name}]: $message")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A continuación, dentro de nuestra función &lt;code&gt;onCreate()&lt;/code&gt; vamos a agregar la invocación a la función &lt;code&gt;setOnClickListener()&lt;/code&gt; de nuestro botón.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;button_launch.setOnClickListener {
   // Dentro vamos a escribir nuestra primera corutina
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vamos con las corutinas
&lt;/h2&gt;

&lt;p&gt;Vamos a escribir un ejemplo bastante común, vamos a simular la invocación a dos servicios que nos retornarán valores aleatorios.&lt;/p&gt;

&lt;p&gt;Para conseguir esto primero escribiremos un par de funciones como te las presento a continuación, estas funciones van a escribir en los logs en qué hilo se está ejecutando, luego va a esperar un determinado tiempo en milisegundos y, finalmente, retornarán un resultado (estamos retornando valores &lt;code&gt;String&lt;/code&gt; pero también podríamos retornar otro tipo de valor):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;suspend fun getApiResult1 (): String {
    log("Get result from suspend function 1")
    delay(3000) // milisegundos
    return "result 1"
}

suspend fun getApiResult2 (): String {
    log("Get result from suspend function 2")
    delay(1500) // milisegundos
    return "result 2"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De estas dos funciones &lt;em&gt;suspendidas&lt;/em&gt; es importante notar el uso de la función &lt;code&gt;delay()&lt;/code&gt; la cual cumple un rol similar a &lt;code&gt;Thread.sleep()&lt;/code&gt; pero sin bloquear el hilo y debido a que en sí misma es también una función suspendida, la regla nos indica que solo se pueden ejecutar desde una corutina o dentro de otra función suspendida (se lee redundante pero es así). &lt;/p&gt;

&lt;p&gt;Ahora vamos a armar la implementación de la corutina con su correspondiente punto de entrada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;button_launch.setOnClickListener {
    // Dentro vamos a escribir nuestra primera corutina
    CoroutineScope(Dispatchers.Main).launch {
        executeRequest()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí también estamos haciendo uso de la función &lt;code&gt;withContext()&lt;/code&gt; y mediante &lt;code&gt;Dispatchers.Main&lt;/code&gt; le estamos indicando que la ejecución de esta corutina empezará en el hilo principal. Adicionalmente, hacemos uso de la función launch la cual marcará el inicio de la corutina.&lt;/p&gt;

&lt;p&gt;Por razones ilustrativas vamos a agregar un par de funciones adicionales, primero esta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;suspend fun executeRequest() = withContext(Dispatchers.IO) {
    val result1 = getApiResult1()
    showResult(result1)
    val result2 = getApiResult2()
    showResult(result2)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí también estamos haciendo uso de la función &lt;code&gt;withContext()&lt;/code&gt; el cual especificará que el bloque de código que encierra se va a suspender en el grupo de hilos que determina el &lt;em&gt;Dispatcher&lt;/em&gt;, en este caso &lt;code&gt;Dispatchers.IO&lt;/code&gt;, el cual &lt;strong&gt;está optimizado para la realización de tareas de networking y escritura en disco&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si intentamos ejecutar el código hasta aquí (espero que lo intentes), seguro la aplicación se va a romper ¿alguna idea del por qué? Dale una vuelta o checka la excepción que salió en tu consola.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Only the original thread that created a view hierarchy can touch its views.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pero ¿qué pasó? bueno, resulta que gracias al &lt;code&gt;withContext(Dispatchers.IO)&lt;/code&gt; esta última función se está ejecutando en los hilos de &lt;em&gt;IO&lt;/em&gt; y no en el &lt;em&gt;Main Thread&lt;/em&gt; o Hilo de UI. Vamos, entonces, a corregir este problema agregando una última función:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;suspend fun sendResultToMainThread(result: String) = withContext(Dispatchers.Main){
    log("Display $result")
    showResult(result)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si lo hiciste bien podrás apreciar lo siguiente en tu consola de Logcat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DefaultDispatcher-worker-1]: Get result from suspend function 1
[main]: Display result 1
[DefaultDispatcher-worker-1]: Get result from suspend function 2
[main]: Display result 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y listo, podemos apreciar los cambios que se van haciendo a medida que vamos ejecutando cada paso de nuestra pequeña aplicación. Ojo que no hemos empleado un adecuado diseño y hemos puesto todo dentro del &lt;em&gt;Activity&lt;/em&gt;, pero la intención es ilustrar cómo funcionan los cambios de contexto durante la ejecución de la corutina y las funciones suspendidas.&lt;/p&gt;

&lt;p&gt;Si les gustó este artículo, podría continuar profundizando en el tema y repasar otros conceptos.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>coroutines</category>
    </item>
    <item>
      <title>Mi nuevo proyecto: Codalot Podcast</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Sun, 29 Mar 2020 04:38:33 +0000</pubDate>
      <link>https://forem.com/devpicon/mi-nuevo-proyecto-codalot-podcast-1lnj</link>
      <guid>https://forem.com/devpicon/mi-nuevo-proyecto-codalot-podcast-1lnj</guid>
      <description>&lt;h3&gt;
  
  
  Desarrollo móvil y tecnología en un solo podcast
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Desde octubre del año pasado (2019) dejé de participar como co-host de Android Dev Podcast en español. Estoy agradecido por el tiempo porque me brindó muy buenas lecciones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tras mi salida del programa de podcast en el que participé durante un año, andaba dándole vueltas a diversas ideas para dedicar mi tiempo.&lt;/p&gt;

&lt;p&gt;Hasta el momento debo decir que participar de un podcast me parece una experiencia genial. La posibilidad de entrevistar a otros desarrolladores o profesionales, plantearles preguntas para aprender y conocer más de lo que hacen, intercambiar ideas y, sobretodo, compartir todo este con la comunidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iniciando la creación de un podcast desde cero
&lt;/h3&gt;

&lt;p&gt;Con esto en mente decidí armar mi propio podcast y, como nos pasa con las variables, decidir qué nombre ponerle fue uno de los aspectos más difíciles de decidir. Porque no se trata solo de ponerle un nombre y ya, la elección del nombre va acompañada de preguntas como ¿será un podcast personal o de tecnología? y si será de tecnología ¿el nombre debe brindar la opción de abrir la temática a temas más allá del desarrollo móvil o no?, ¿el nombre debería estar en inglés o en español? ¿será lo suficientemente corto para pronunciar pero sea fácil de recordar también?&lt;/p&gt;

&lt;p&gt;Al final de este proceso quedó &lt;em&gt;&lt;a href="https://anchor.fm/codalot"&gt;Codalot&lt;/a&gt;&lt;/em&gt; y que sería un podcast que iniciaría hablando de desarrollo móvil (mi campo actual de trabajo), pero que eventualmente, en futuras temporadas pudiera tocar temas nuevos como desarrollo &lt;em&gt;front&lt;/em&gt;, &lt;em&gt;backend&lt;/em&gt;, &lt;em&gt;machine learning&lt;/em&gt;, inteligencia artificial, periodismo de tecnología, etc.&lt;/p&gt;

&lt;p&gt;¿Por qué Códalot? &lt;em&gt;&lt;a href="https://www.urbandictionary.com/define.php?term=Long%20Story%20Short"&gt;long-short story&lt;/a&gt;&lt;/em&gt;: antiguamente, era el nombre que recibió una iniciativa educativa que tuvimos con un buen amigo hace muchos años atrás y que, con el tiempo y las circunstancias de la vida, cayó en desuso. Tiempo atrás hablé con este amigo y me dejó a mi albedrío decidir qué hacer con el nombre. Debo confesar que no fue el nombre que había decidido ponerle al podcast, pero al final, después de indagar un poco, el nombre sonaba bien. Codalot se escucha como Lancelot, Camelot o &lt;em&gt;Code-a-lot&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ya tenemos un nombre y ¿dónde se va a alojar nuestro podcast?&lt;/p&gt;

&lt;h3&gt;
  
  
  Buscando alojamiento para nuestro podcast
&lt;/h3&gt;

&lt;p&gt;Otro desafío en nuestro camino rumbo a convertirnos en P̵o̵k̵é̵m̵o̵n̵ ̵m̵a̵s̵t̵e̵r̵s̵ &lt;em&gt;Podcasters&lt;/em&gt; es encontrar un buen alojamiento para nuestros episodios.&lt;/p&gt;

&lt;p&gt;Aquí hay que considerar varias cosas. ¿Queremos tener el control sobre todo aspecto de nuestro podcast o que alguien más nos provea del servicio? Y si queremos que alguien nos provea del servicio ¿Buscamos un servicio gratuito o uno pago?&lt;/p&gt;

&lt;p&gt;Si quisiera hacerlo todo desde cero habría que considerar armar una landing page para el podcast, reservar un repositorio para nuestros episodios (puede ser pago como Amazon S3 o gratuito como Archive.org), generar el RSS de nuestro programa y crear cuentas en cada servicio de distribución (&lt;a href="http://podcasters.spotify.com"&gt;Spotify for Podcasters&lt;/a&gt;, &lt;a href="https://podcastsconnect.apple.com/"&gt;Podcast Connect by Apple&lt;/a&gt;, &lt;a href="https://play.google.com/music/podcasts/portal/#p:id=playpodcast/all-podcasts"&gt;Google Play Podcast Portal&lt;/a&gt;, Pocketcast, etc).&lt;/p&gt;

&lt;p&gt;Como no quería invertir mucho tiempo en todo ello, me fui por una plataforma que me proveyera de todo lo necesario para que solo me preocupe por grabar. De todos los servicios que vi me quedé con el servicio gratuito que brinda Anchor.fm.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué implica usar Anchor.fm?
&lt;/h3&gt;

&lt;p&gt;Implica que solo puedes tener un podcast por cuenta, que agreguen su loguito en el arte visual de tu podcast, que tengas la posibilidad de monetizar (si vives en EUA), que puedas grabar segmentos a través de sus diferentes plataformas, pero el principal valor fue que te distribuye en una buena cantidad de servicios automáticamente (incluyendo Spotify, excluyendo Apple Podcast).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Es importante mencionar que si deseas acceder a los &lt;em&gt;stats&lt;/em&gt; de Spotify, puedas reclamar tu podcast empleando el correo que asignaste a tu podcast. No es un proceso difícil, pero es importante tenerlo en cuenta.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si eventualmente el programa crece y quisiera llevarlo a un plano más profesional, tal vez requiera de otro tipo de servicios; como todavía es prematuro no he revisado que tan complicado podría ser abandonar la plataforma.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Y qué onda con el hardware?
&lt;/h3&gt;

&lt;p&gt;Para empezar un podcast diría que lo más importante es el contenido y que así juntito está la calidad del audio. Como muchas cosas, soy de la idea que lo primero es empezar y ver si le agarramos el gusto. Cuando participaba del anterior programa lo hacía con el micrófono de la laptop, luego de agarrarle el gusto invertí un poco de dinero para comprar un micrófono.&lt;/p&gt;

&lt;p&gt;El micrófono que adquirí fue un &lt;a href="https://www.bluedesigns.es/products/yeti/"&gt;Yeti by Blue&lt;/a&gt;. Ya conocía este micrófono porque lo había empleado años atrás cuando me tocó grabar un curso para una plataforma online y conocía de sus opciones. Además de proveer una buena calidad de sonido, los modos que trae consigo te permiten usarlo también para entrevistas presenciales con más de una persona. Les recomiendo revisarlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Y el software?
&lt;/h3&gt;

&lt;p&gt;Para grabar cada episodio me valgo de la plataforma &lt;a href="https://zencastr.com/"&gt;Zencastr&lt;/a&gt;, en su plan gratuito te permite contar con 3 participantes por grabación, te brinda almacenamiento local e integración con Dropbox, lo cual permite que al final de cada sesión tengas el audio por separado de cada participante en la nube, esto es suficiente para luego pasar a la post-producción.&lt;/p&gt;

&lt;p&gt;Para juntar los audios, editarlos y generar el archivo de audio que subiré a Anchor empleo &lt;a href="https://www.audacityteam.org/"&gt;Audacity&lt;/a&gt;, una aplicación gratuita muy conocida que permite realizar ediciones de audio. Esto es suficiente para preparar el audio final.&lt;/p&gt;

&lt;h3&gt;
  
  
  Planeación de cada episodio
&lt;/h3&gt;

&lt;p&gt;El contenido es un aspecto importante del podcast. Para ello lo que hice fue planear de antemano sobre qué temas quería hablar en una primera temporada.&lt;/p&gt;

&lt;p&gt;Recibí el buen consejo de planificar de 6 en 6 los episodios. Partiendo por enumerar un título genérico de la temática de cada episodio y, luego, por cada uno, coordinar la participación del invitado, enumerar las preguntas o dudas que puedan surgir de uno mismo o de la comunidad, armar un pequeño delineación de la estructura del episodio (incluyendo la apertura, la presentación y el cierre).&lt;/p&gt;

&lt;p&gt;También, es bueno practicar un poco las transiciones, familiarizarse con el contenido del tema a tratar, todo esto con el fin de hacer que la dinámica de cada episodio sea fluída. Igual, es algo que se va mejorando con el tiempo y a medida de que se vaya ganando experiencia.&lt;/p&gt;

&lt;p&gt;Sin duda alguna entrar al mundo del &lt;em&gt;podcasting&lt;/em&gt; es genial, espero que este contenido les sirva de referencia por si algún día se animan a incursionar en ello. No dejen de escuchar mi podcast a través de la principales plataformas de streaming (los enlaces de cada plataforma se los dejo a continuación). Si tienen comentarios o sugerencias no duden en hacérmelas llegar. Saludos y buena cuarentena.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://open.spotify.com/embed-podcast/show/1iyrRtXu0hrOQJyA7vdGiX"&gt;Codalot en Spotify&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://podcasts.apple.com/cl/podcast/codalot-podcast/id1502209502"&gt;Codalot en Podcast by Apple&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://playmusic.app.goo.gl/?ibi=com.google.PlayMusic&amp;amp;isi=691797987&amp;amp;ius=googleplaymusic&amp;amp;apn=com.google.android.music&amp;amp;link=https://play.google.com/music/m/Ilyqsddhwz5e3jbpy47apsijaji?t%3DCodalot_Podcast%26pcampaignid%3DMKT-na-all-co-pr-mu-pod-16"&gt;Codalot en Google Play Music&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>kotlin</category>
      <category>techtalks</category>
      <category>android</category>
    </item>
    <item>
      <title>Android — ¿Cómo evitar que los logs de tu app desaparezcan?</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 30 Sep 2019 22:44:11 +0000</pubDate>
      <link>https://forem.com/devpicon/android-como-evitar-que-los-logs-de-tu-app-desaparezcan-1p18</link>
      <guid>https://forem.com/devpicon/android-como-evitar-que-los-logs-de-tu-app-desaparezcan-1p18</guid>
      <description>&lt;h3&gt;
  
  
  Android — ¿Cómo evitar que los logs de tu app desaparezcan?
&lt;/h3&gt;

&lt;p&gt;Quizá muchos ya sabían sobre esto, pero cuando uno emplear Logcat desde Android Studio y nuestra app sufre un &lt;em&gt;crash&lt;/em&gt; los logs se reinician.&lt;/p&gt;

&lt;p&gt;Esta situación se debe a que con la configuración por defecto Android Studio nos mostrará los logs solo del proceso seleccionado y cuando el proceso se muere (cuando nuestra app crashea) deja de registrar los logs.&lt;/p&gt;

&lt;p&gt;Sin embargo, esto se puede evitar haciendo lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eb8tcXRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6c7SdhlDyo6nOh8-ZKrzQQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eb8tcXRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6c7SdhlDyo6nOh8-ZKrzQQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En la parte superior derecha de esta sección desplegamos la lista en la que suele estar seleccionada la opción &lt;em&gt;Show only selected application&lt;/em&gt; y elegimos la opción &lt;em&gt;Edit Filter Configuration&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A continuación, crearemos un nuevo filtro y en el campo &lt;em&gt;Package Name&lt;/em&gt; colocaremos el nombre del paquete que querramos loguear (Ej. &lt;strong&gt;dev.picon.android.myapp&lt;/strong&gt; )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F7Ve9sgH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A1iosRyKg9hGHSE2YHc0rmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F7Ve9sgH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A1iosRyKg9hGHSE2YHc0rmg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y listo! Esta configuración será suficiente para que por más que se muera nuestra app los logs continúen siendo visibles para nosotros.&lt;/p&gt;




</description>
      <category>logcat</category>
      <category>androidstudio</category>
      <category>tips</category>
      <category>android</category>
    </item>
    <item>
      <title>Android — ¿Por qué no estás escribiendo tests? (1)</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 19 Aug 2019 03:45:11 +0000</pubDate>
      <link>https://forem.com/devpicon/android-por-que-no-estas-escribiendo-tests-1-4cll</link>
      <guid>https://forem.com/devpicon/android-por-que-no-estas-escribiendo-tests-1-4cll</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JPKW0nGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ag5M7HINrNGB4V8Tc1pieBw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JPKW0nGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ag5M7HINrNGB4V8Tc1pieBw.jpeg" alt=""&gt;&lt;/a&gt;Picture by &lt;a class="comment-mentioned-user" href="https://dev.to/devpicon"&gt;@devpicon&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Android — ¿Por qué no estás escribiendo tests? (1)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Be clean, be testeable
&lt;/h4&gt;

&lt;p&gt;Es un tema recurrente año tras año: un buen número de desarrolladores no escriben &lt;em&gt;tests&lt;/em&gt; (pruebas) para sus aplicaciones y las razones puede ser diversas: Desde “no sé cómo escribir &lt;em&gt;tests&lt;/em&gt;” hasta “escribir &lt;em&gt;tests&lt;/em&gt; me quita tiempo”. Siempre habrá razones para no escribir &lt;em&gt;tests&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Y, por el contrario, siempre habrá buenas razones para escribir &lt;em&gt;tests&lt;/em&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Los &lt;em&gt;tests&lt;/em&gt; siempre harán tu código más fiable aumentando tu certeza de que lo que estás programando, efectivamente, cumple su propósito.&lt;/li&gt;
&lt;li&gt;Contar con &lt;em&gt;tests&lt;/em&gt; te ayudará a saber si alguna modificación introducida posteriormente rompe alguna otra funcionalidad de tu aplicación.&lt;/li&gt;
&lt;li&gt;Evitar el “titánico” esfuerzo de mantenimiento de código que suele haber cuando no hay &lt;em&gt;tests&lt;/em&gt;. El tiempo es dinero.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En este primer artículo desarrollaré un poco la parte teórica y ciertos lineamientos a tener en cuenta al momento de querer introducir &lt;em&gt;tests&lt;/em&gt; en una aplicación con código &lt;em&gt;legacy&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  ¿Qué puedo hacer para hacer mi código “&lt;em&gt;testeable”&lt;/em&gt;?
&lt;/h4&gt;

&lt;p&gt;Aunque en la vida uno vive escuchando de cuando en cuando acerca de los &lt;em&gt;tests&lt;/em&gt; y lo impresionante que son, creo que pocos realmente te orientan a hallar un proceso para hacer tu código &lt;em&gt;testeable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGXKtLmT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1015/1%2AMUVefJblPpImirMIba54Vg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGXKtLmT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1015/1%2AMUVefJblPpImirMIba54Vg.jpeg" alt=""&gt;&lt;/a&gt;The Test Pyramid&lt;/p&gt;

&lt;p&gt;Partamos por algo básico y que seguramente ya han visto antes “la pirámide de los &lt;em&gt;tests&lt;/em&gt;”.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;La “Pirámide de los&lt;/em&gt; Tests_” es una metáfora que nos hace lleva a agrupar las pruebas de software en bloques de diferente granularidad. También, nos brinda una idea de cuántas pruebas deberíamos tener en dichos grupos. A pesar de que el concepto de la Pirámide de los_ Tests _ha estado presente por buen tiempo, los equipos siguen entrampados en cómo ponerlo en práctica. — _The Practical Test Pyramid (traducción libre)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para no entrar en mucha discusión respecto a la pirámide, la figura se puede interpretar de la siguiente manera:&lt;/p&gt;

&lt;p&gt;_Unit Tests — _la base está conformada por pruebas unitarias; estas son menos costosas y si tuvieramos que priorizar el esfuerzo para escribir pruebas debería ser en este bloque, principalmente, porque no hay una dependencia fuerte con frameworks y bibliotecas de código.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Service Tests—_el bloque del medio no se refiere solo a probar servicios; en realidad implica probar la integración entre componentes y las diferentes capas de nuestra aplicación. La priorización en esfuerzo es media, lo cual implica que el desarrollo de estas pruebas cuenta con una menor prioridad que los _unit tests&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;_User Interface Tests — _finalmente, en la cúspide de nuestra pirámide se encuentran las pruebas de UI. El desarrollo de pruebas de UI guarda consigo cierta complejidad dependiendo de la aplicación que estemos probando. Proporcionalmente hablando, en muchos casos la cantidad de pruebas será menor que la de las otras capas.&lt;/p&gt;

&lt;h4&gt;
  
  
  Partamos con los “Unit Tests”
&lt;/h4&gt;

&lt;p&gt;Un buen punto de inicio es comenzar a escribir &lt;em&gt;unit tests&lt;/em&gt; (pruebas unitarias). Estas pruebas tienen como objetivo verificar el comportamiento de las funciones y la lógica de nuestras unidades de programación, las clases.&lt;/p&gt;

&lt;p&gt;Como hablamos antes, se suele asumir que todos saben cómo hacerlas y, por ello, no se suele marcar un camino para llegar a ellas, pero en esta ocasión vamos a trazar algunos lineamientos y, posteriormente, lo traduciremos en una serie de tareas a seguir.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Las funciones y clases como mínimo deben cumplir con algunos de los principios SOLID: &lt;strong&gt;&lt;em&gt;The Single Responsibility&lt;/em&gt;&lt;/strong&gt; (Responsabilidad simple) que nos menciona que una clase debería tomar responsabilidad sobre una sola parte de nuestra aplicación; &lt;strong&gt;&lt;em&gt;Interface Segregation&lt;/em&gt;&lt;/strong&gt; (Segregación de interfaces) que implica que varias funcionalidades podrían estar definidas en varias abstracciones en lugar de una sola y, &lt;strong&gt;&lt;em&gt;Dependency Inversion&lt;/em&gt;&lt;/strong&gt; (Inversión de dependencia) que implica evitar el acoplamiento entre clases a través de generar dependencias sobre abstracciones.&lt;/li&gt;
&lt;li&gt;Cuando una clase o función no cumpla con lo anterior, será una buena razón para comenzar a refactorizar, en un principio no haremos grandes cambios al diseño de la aplicación sino que comenzaremos a dividir funciones con múltiples responsabilidades en funciones de una sola responsabilidad. De ese modo separaremos nuestra lógica en funciones más pequeñas o incluso las terminaremos moviendo hacia otras clases.&lt;/li&gt;
&lt;li&gt;Nuestros &lt;em&gt;unit tests&lt;/em&gt; seguirán la estructura &lt;em&gt;Given-When-Then&lt;/em&gt;, una estructura que tomaremos prestada de BDD y que se traduciría de la siguiente manera:
&lt;strong&gt;“Dado (&lt;em&gt;Given&lt;/em&gt;) un estado de nuestro componente o Dada alguna condición; Cuando (&lt;em&gt;When&lt;/em&gt;) una acción se realiza o se invoca a una función con un conjunto de parámetros; Entonces (&lt;em&gt;Then&lt;/em&gt;) deberíamos obtener un resultado esperado”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Si hicimos bien la refactorización señalada en el punto 2, podremos &lt;em&gt;mockear&lt;/em&gt; cualquier dependencia de la clase que queramos probar. Cuando me refiero a &lt;em&gt;mockear&lt;/em&gt;, me refiero a que cualquier dependencia las podemos inflar o crear haciendo uso de una abstracción en conjunto con una concreción propia.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bueno, teniendo esto en mente, en el siguiente artículo traduciré estos lineamientos a un ejercicio más práctico.&lt;/p&gt;

&lt;h4&gt;
  
  
  Referencias
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The Practical Test Pyramid — &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GivenWhenThen — &lt;a href="https://martinfowler.com/bliki/GivenWhenThen.html"&gt;https://martinfowler.com/bliki/GivenWhenThen.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SOLID Principles: Explanation and examples — &lt;a href="https://itnext.io/solid-principles-explanation-and-examples-715b975dcad4"&gt;https://itnext.io/solid-principles-explanation-and-examples-715b975dcad4&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>androidappdevelopm</category>
      <category>testing</category>
      <category>spanish</category>
      <category>android</category>
    </item>
    <item>
      <title>Kotlin - ¿Funciones como operadores aritméticos? Sí, con Infix functions</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Tue, 11 Jun 2019 14:32:40 +0000</pubDate>
      <link>https://forem.com/devpicon/kotlin-funciones-como-operadores-aritmeticos-si-con-infix-functions-2h7</link>
      <guid>https://forem.com/devpicon/kotlin-funciones-como-operadores-aritmeticos-si-con-infix-functions-2h7</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hFVtZhv8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AMCU8J5-roudxIIYt1U1J1A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hFVtZhv8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AMCU8J5-roudxIIYt1U1J1A.jpeg" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Trabajando algunas cosas como operadores
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Esta es una adaptación libre basado en el artículo en inglés “&lt;/em&gt;&lt;a href="https://medium.com/makingtuenti/infix-functions-in-kotlin-2db3d3142dd2"&gt;&lt;em&gt;Infix functions in Kotlin — Making Tuenti&lt;/em&gt;&lt;/a&gt;&lt;em&gt;” escrito por Arturo Gutierrez.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Cuando escribes una función regular o una &lt;em&gt;Extension Function&lt;/em&gt;, es posible emplearlas con &lt;a href="https://es.wikipedia.org/wiki/Notaci%C3%B3n_de_infijo"&gt;la notación de infijo (o infix notation en inglés)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vamos a armar un breve ejemplo que nos ayude a entender los &lt;em&gt;infix&lt;/em&gt; &lt;em&gt;functions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Definamos algunos enumeradores y una clase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum class ZodiacSign {
    ARIES, TAURUS, GEMINI, CANCER, LEO, VIRGO, LIBRA, 
    SCORPIO, SAGITTARIUS, CAPRICORN, AQUARIUS, PISCES  
}

enum class Saint {
    MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, SHAKA, DOHKO, 
    MILO, AIOROS, SHURA, CAMUS, AFRODITA  
}

data class GoldenSaint( val saint : Saint, val zodiacSign : ZodiacSign)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Los nombres son muy explícitos, pero por si las dudas, se refiere a los signos zodiacales y los nombres de los caballeros dorados de un conocido dibujo japonés llamado “Caballeros del Zodiaco” (o Saint Seiya).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Si precisaramos crear un nuevo objeto la sintaxis habitual sería la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    val virgoGoldenSaint = GoldenSaint(Saint. SHURA, ZodiacSign. VIRGO )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La idea es simplificar la forma de crear un nuevo objeto agregando una función al &lt;em&gt;enum class&lt;/em&gt;  &lt;strong&gt;Saint&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum class Saint {
    MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, SHAKA, 
    DOHKO, MILO, AIOROS, SHURA, CAMUS, AFRODITA;

    fun of(zodiacSign: ZodiacSign) = GoldenSaint( this, zodiacSign)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con la función &lt;strong&gt;of&lt;/strong&gt; ganamos un poco de legibilidad a la creación de un objeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    val sagittariusGoldenSaint = Saint. AIOROS.of(ZodiacSign. SAGITTARIUS )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podríamos mejorarla un poco más mediante la importación estática de cada elemento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    val sagittariusGoldenSaint = AIOROS.of( SAGITTARIUS )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hasta allí va luciendo mejor, pero aún se podría mejorar. Para ello le agregaremos la palabra reservada &lt;strong&gt;infix&lt;/strong&gt; previo al nombre de nuestra función de esta manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum class Saint {
    MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, 
    SHAKA, DOHKO, MILO, AIOROS, SHURA, CAMUS, AFRODITA;

    infix fun of(zodiacSign: ZodiacSign) = GoldenSaint( this, zodiacSign)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Y qué conseguimos con ello? Darle a la función una forma similar a la de un operador aritmético tal como lo podemos ver a continuación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    val sagittariusGoldenSaint = AIOROS of SAGITTARIUS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Luce mejor verdad? Esto constituye un acercamiento a un lenguaje más natural haciendo nuestro código más &lt;strong&gt;legible y conciso&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consideraciones
&lt;/h3&gt;

&lt;p&gt;Algunas consideraciones para aplicar &lt;em&gt;infix&lt;/em&gt; son las siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Puede aplicarse a &lt;a href="https://medium.com/@devpicon/android-java-y-si-le-agregamos-funciones-a-la-clase-con-kotlin-346518595c3#.exrerpaht"&gt;&lt;em&gt;extension functions&lt;/em&gt;&lt;/a&gt; y funciones de clase.&lt;/li&gt;
&lt;li&gt;La función solo puede recibir un único parámetro.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  P.D.
&lt;/h4&gt;

&lt;p&gt;Puede encontrar más artículos sobre Kotlin en la publicación &lt;a href="https://medium.com/kotlin-dev-reactor"&gt;&lt;strong&gt;Kotlin Dev Reactor&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Referencias:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/makingtuenti/infix-functions-in-kotlin-2db3d3142dd2"&gt;Infix functions in Kotlin — Making Tuenti&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://es.wikipedia.org/wiki/Notaci%C3%B3n_de_infijo"&gt;Notación de infijo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kotlinlang.org/docs/reference/functions.html#infix-notation"&gt;Infix notation — Kotlin Programming Language documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;¡Gracias por leer el artículo, significa mucho para mi! Si lo disfrutaste o fue de utilidad por favor recomiéndalo y compartelo con tus amigos.&lt;/p&gt;

&lt;p&gt;Me puedes encontrar en &lt;a href="http://twitter.com/@DevPicon"&gt;Twitter&lt;/a&gt;, &lt;a href="http://github.com/DevPicon"&gt;Github&lt;/a&gt; y &lt;a href="https://www.linkedin.com/in/armandopicon/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>kotlin</category>
      <category>android</category>
      <category>functional</category>
    </item>
    <item>
      <title>¿Qué nos dejó el Google I/O 2019?</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 13 May 2019 04:32:17 +0000</pubDate>
      <link>https://forem.com/devpicon/que-nos-dejo-el-google-i-o-2019-3k8i</link>
      <guid>https://forem.com/devpicon/que-nos-dejo-el-google-i-o-2019-3k8i</guid>
      <description>&lt;h4&gt;
  
  
  Para un Android Developer
&lt;/h4&gt;

&lt;p&gt;Sin duda ha sido una edición interesante la de este año donde, a mi entender, hay mucho por procesar; en particular, si eres Android Developer.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2ABcG7VpF79qnDz5Zl" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2ABcG7VpF79qnDz5Zl"&gt;&lt;/a&gt;Una foto con la banda latinoamericana en el Google I/O 2019&lt;/p&gt;

&lt;p&gt;Por cuarta ocasión tuve la oportunidad de asistir al Google I/O que se viene dando en el &lt;em&gt;Shoreline Amphitheatre&lt;/em&gt;, lugar en el que en medio de un ambiente de fiesta se presentan las diferentes novedades respecto a tecnologías que desarrolla Google.&lt;/p&gt;

&lt;p&gt;El evento contó con sesiones que se desarrollaron en diversos espacios en conjunto con el anfiteatro, además de espacios temáticos en los que se podía conversar con ingenieros que vienen desarrollando diversas tecnologías: &lt;strong&gt;Android&lt;/strong&gt; , &lt;strong&gt;Fluter+AR&lt;/strong&gt; , &lt;strong&gt;Android Auto&lt;/strong&gt; , &lt;strong&gt;Chrome OS&lt;/strong&gt; , &lt;strong&gt;Wear OS&lt;/strong&gt; , &lt;strong&gt;Firebase&lt;/strong&gt; , &lt;strong&gt;Assistant&lt;/strong&gt; , etc. Adicionalmente, hubo un espacio para los &lt;em&gt;App Reviews&lt;/em&gt; y los &lt;em&gt;Office Hour&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Las sesiones del evento ya &lt;a href="https://www.youtube.com/playlist?list=PLOU2XLYxmsILVTiOlMJdo7RQS55jYhsMi" rel="noopener noreferrer"&gt;se encuentran disponibles en el canal de Google Developers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A continuación, comentaré un poco sobre las sesiones que tuve oportunidad de asistir.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Google Keynote
&lt;/h4&gt;

&lt;p&gt;Algunas cosas que debo resaltar del keynote son las siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hoy en día Google viene trabajando de la mano con la medicina para la detección temprana del cáncer mediante uso de modelos e inteligencia artificial.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;proyecto Duplex&lt;/strong&gt; sigue avanzando, ahora no solo permitirá que nuestro asistente pueda interactuar con personas en la vida real para efectuar reservas, atender llamadas cuando estamos ocupados, etc. sino que también podrá interactuar automáticamente con webs para realizar operaciones que nos quitan tiempo.&lt;/li&gt;
&lt;li&gt;Hay avances en cuestión de accesibilidad, ahora será posible contar con comunicaciones con transcripciones en vivo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proyecto Euphonia&lt;/strong&gt; (&lt;a href="http://g.co/euphonia" rel="noopener noreferrer"&gt;http://g.co/euphonia&lt;/a&gt;) es un proyecto que emplea modelos entrenados para personas con dificultades de habla.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OAdegPmkK-o"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se mostró el uso de herramientas como Google Translator y su capacidad de uso en mercados emergentes con dispositivos de bajo costo y bajas prestaciones. Es increíble la capacidad de compactar todos estos modelos para que su uso no requiera tanto espacio de almacenamiento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Developer Keynote
&lt;/h4&gt;

&lt;p&gt;Tras lo visto en el Google Keynote, nos tocó presenciar el Keynote para developers el cual toca aspectos más técnicos de las herramientas de Google. En esta ocasión esta &lt;em&gt;keynote&lt;/em&gt; fue abierta por Thomas Kurian, actual CEO de Google Cloud. Si bien la keynote habla sobre varias tecnologías, me enfocaré en los anuncios hechos para  &lt;strong&gt;Android&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android pasa a tornarse &lt;em&gt;Kotlin-first&lt;/em&gt; con mayor fuerza que antes y por ello muchas de las actualizaciones en las bibliotecas que componen Jetpack vendrán enfocadas en dicho lenguaje.&lt;/li&gt;
&lt;li&gt;Se agregó un nuevo API a Jetpack llamado &lt;a href="https://developer.android.com/training/camerax" rel="noopener noreferrer"&gt;&lt;strong&gt;CameraX&lt;/strong&gt;&lt;/a&gt; que busca estandarizar las implementaciones de cámaras de forma retrocompatible y hasta un 90% de dispositivos en le mercado.&lt;/li&gt;
&lt;li&gt;También, se está trabajando una biblioteca llamada &lt;a href="https://developer.android.com/jetpack/compose" rel="noopener noreferrer"&gt;&lt;strong&gt;Jetpack Compose&lt;/strong&gt;&lt;/a&gt; (en desarrollo) que permitirá un desarrollo reactivo de cara a la UI.&lt;/li&gt;
&lt;li&gt;El equipo detrás de &lt;strong&gt;Android Studio&lt;/strong&gt; realizó un &lt;em&gt;feature freeze&lt;/em&gt; y se puso a trabajar sobre los bugs más importantes y a mejorar todas las herramientas desde sus bases, &lt;a href="https://android-developers.googleblog.com/2019/05/android-studio-35-beta.html" rel="noopener noreferrer"&gt;estas mejoras vendrán como parte de la versión 3.5&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Habrá una nueva característica llamada &lt;strong&gt;in-app updates&lt;/strong&gt; que permitirá realizar actualizaciones de nuestras aplicaciones sin la necesidad de esperar a que la actualización provenga desde la Play Store.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Otras sesiones que vi
&lt;/h4&gt;

&lt;p&gt;A continuación, les dejaré la lista de sesiones a las que tuve ocasión de asistir:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Aunque es una charla de introducción, nos trae las novedades que hay en Android.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;En esta plática se nos explica cómo trabaja Kotlin por detrás.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;En esta plática se nos explica cómo trabaja el nuevo API CameraX.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Me encantó esta plática que dieron &lt;a href="https://medium.com/u/d5885adb1ddf" rel="noopener noreferrer"&gt;Florina Muntenescu&lt;/a&gt; y &lt;a href="https://medium.com/u/55a38e86cfa7" rel="noopener noreferrer"&gt;Yigit Boyar&lt;/a&gt;, en la que juntos exploran diversos modelos de arquitectura en función al enfoque que uno le quiera dar. La lección final es “no te diremos cuál usar, todo dependerá de la aplicación que estés construyendo”, sin embargo, es una charla recomendable para ver porque te van mostrando los diversos aspectos que involucran el elegir y seguir el camino hacia el establecimiento de una arquitectura. Mi percepción sobre esta plática es que de tanto ver a la comunidad discutir sobre la arquitectura que uno debe emplear, quisieron dejar clara su posición al respecto.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Esta plática comienza con el repaso de los principios que rigen a las corutinas y luego va más allá, terminan mostrándonos como diversos componentes toman las corutinas y las integran para mejorar su funcionamiento.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;La clásica charla con los responsables de cada equipo involucrado con el desarrollo de Android.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/videoseries"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Si queremos ir un poco más a fondo de cómo trabaja Android, esta charla es buenísima. Nos ayuda a tener una mejor comprensión de cómo trabaja la maquina virtual de Android.&lt;/p&gt;

&lt;p&gt;Pues hasta aquí con las pláticas a las que pude asistir, me quedaron varias pendientes que espero ir revisando en los próximos días. No dejen de revisarlas y seguir aprendiendo.&lt;/p&gt;

&lt;p&gt;BTW Me quedé con las ganas de conseguir un Pixel 3a y un Smartwatch con Wear OS, pero ya será para una próxima ocasión.&lt;/p&gt;




</description>
      <category>android</category>
      <category>español</category>
      <category>androiddevelopment</category>
      <category>androiddev</category>
    </item>
  </channel>
</rss>
