<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Armando Picón</title>
    <description>The latest articles on DEV Community by Armando Picón (@devpicon).</description>
    <link>https://dev.to/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>DEV Community: Armando Picón</title>
      <link>https://dev.to/devpicon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devpicon"/>
    <language>en</language>
    <item>
      <title>🔐 Beyond SSL Pinning: mTLS, Backend Security &amp; Real-World Mobile Architecture (Part 3)</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 04 May 2026 21:44:39 +0000</pubDate>
      <link>https://dev.to/devpicon/beyond-ssl-pinning-mtls-backend-security-real-world-mobile-architecture-part-3-oeb</link>
      <guid>https://dev.to/devpicon/beyond-ssl-pinning-mtls-backend-security-real-world-mobile-architecture-part-3-oeb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhpym0964quse1bniok1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhpym0964quse1bniok1.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous parts, we explored SSL pinning across &lt;a href="https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-2pk2"&gt;Android&lt;/a&gt; and &lt;a href="https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-part-2-3p4m"&gt;iOS&lt;/a&gt;, including both certificate and public key approaches.&lt;/p&gt;

&lt;p&gt;But here’s the uncomfortable truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even perfectly implemented pinning is not enough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this final part, we move beyond the client and look at what truly defines a secure mobile architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mutual TLS (mTLS)&lt;/li&gt;
&lt;li&gt;Backend access control&lt;/li&gt;
&lt;li&gt;Defense in depth&lt;/li&gt;
&lt;li&gt;When mobile security actually fails in production&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Why Pinning Is Not the Endgame
&lt;/h2&gt;

&lt;p&gt;Pinning protects the &lt;strong&gt;channel&lt;/strong&gt;, not the &lt;strong&gt;system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✔ Prevents MITM attacks
&lt;/li&gt;
&lt;li&gt;❌ Does NOT prevent unauthorized API access
&lt;/li&gt;
&lt;li&gt;❌ Does NOT validate who is calling your backend
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your API is publicly exposed, anyone can still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Postman
&lt;/li&gt;
&lt;li&gt;Reverse engineer your app
&lt;/li&gt;
&lt;li&gt;Replay requests
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the real question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we ensure that only trusted clients can talk to our backend?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔴 Enter mTLS (Mutual TLS)
&lt;/h2&gt;

&lt;p&gt;Unlike standard TLS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server presents a certificate ✅
&lt;/li&gt;
&lt;li&gt;Client verifies server
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With &lt;strong&gt;mTLS&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server presents certificate ✅
&lt;/li&gt;
&lt;li&gt;Client presents certificate ✅
&lt;/li&gt;
&lt;li&gt;Both sides verify each other
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔐 mTLS Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → Server: Hello
Server → Client: Certificate
Client → Server: Certificate (client identity)
Server → Client: Accept / Reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;✔ What mTLS Solves&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Strong client authentication&lt;/li&gt;
&lt;li&gt;Prevents unauthorized clients (e.g. Postman, curl)&lt;/li&gt;
&lt;li&gt;Removes reliance on API keys alone&lt;/li&gt;
&lt;li&gt;Can partially replace VPN in some architectures&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;⚠️ Why mTLS Is Rare in Mobile&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Because it’s operationally expensive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Securely storing client certificates on device is hard&lt;/li&gt;
&lt;li&gt;Certificates must be rotated&lt;/li&gt;
&lt;li&gt;Risk of extraction on rooted/jailbroken devices&lt;/li&gt;
&lt;li&gt;Complex provisioning process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Most teams underestimate this complexity&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧩 Where mTLS Actually Makes Sense&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise apps (controlled devices)&lt;/li&gt;
&lt;li&gt;MDM-managed environments&lt;/li&gt;
&lt;li&gt;Internal tools&lt;/li&gt;
&lt;li&gt;High-security B2B systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public consumer apps&lt;/li&gt;
&lt;li&gt;Apps distributed via App Store / Play Store&lt;/li&gt;
&lt;li&gt;Large-scale unknown user bases&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧠 Real-World Alternative: Token-Based Security&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of relying on transport-level identity:&lt;/p&gt;

&lt;p&gt;👉 Use &lt;strong&gt;application-level identity&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;App → HTTPS → API Gateway → Auth (JWT / OAuth) → Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;✔ What This Solves&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;User authentication&lt;/li&gt;
&lt;li&gt;Fine-grained authorization&lt;/li&gt;
&lt;li&gt;Revocation&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧱 Defense in Depth (What Actually Works)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A realistic production setup looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mobile App
   ↓
TLS (HTTPS)
   ↓
(Optional) Certificate Pinning
   ↓
API Gateway
   ↓
Auth Layer (JWT / OAuth)
   ↓
Rate Limiting / WAF
   ↓
Microservices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;🔍 Common Mistakes in Mobile Security&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s be blunt:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;❌ “We added SSL pinning, we’re secure”&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No — you protected only the transport layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;❌ Hardcoding API keys in the app&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These will be extracted. Always.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;❌ Trusting the client&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The client is always hostile. Assume compromise.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;❌ Ignoring backend validation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Security belongs to the backend, not the app.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧠 When Mobile Security Fails&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Not because of TLS.&lt;/p&gt;

&lt;p&gt;But because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poor authentication design&lt;/li&gt;
&lt;li&gt;Lack of rate limiting&lt;/li&gt;
&lt;li&gt;Missing monitoring&lt;/li&gt;
&lt;li&gt;Weak backend validation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧭 Practical Recommendations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’re building a modern mobile app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with HTTPS (mandatory)&lt;/li&gt;
&lt;li&gt;Add proper authentication (JWT / OAuth)&lt;/li&gt;
&lt;li&gt;Introduce API Gateway controls&lt;/li&gt;
&lt;li&gt;Add rate limiting &amp;amp; monitoring&lt;/li&gt;
&lt;li&gt;Consider pinning as an extra layer&lt;/li&gt;
&lt;li&gt;Evaluate mTLS only if you truly need it&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🧠 Final Takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Security is not a feature — it’s a system.&lt;/p&gt;

&lt;p&gt;Pinning protects the connection.&lt;br&gt;
 mTLS protects the client identity.&lt;br&gt;
 Backend security protects your business.&lt;/p&gt;

&lt;p&gt;If you ignore the last one, the first two won’t save you.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;👋 Closing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this point, you’ve seen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to implement pinning on Android&lt;/li&gt;
&lt;li&gt;How to implement it on iOS&lt;/li&gt;
&lt;li&gt;And where it actually fits in a real-world architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use it wisely.&lt;/p&gt;

&lt;p&gt;And more importantly — design beyond it.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>security</category>
      <category>backend</category>
      <category>api</category>
    </item>
    <item>
      <title>🔐 SSL Pinning in Mobile Apps: Android &amp; iOS (Practical Guide + Trade-offs) - Part 2</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 04 May 2026 21:25:47 +0000</pubDate>
      <link>https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-part-2-3p4m</link>
      <guid>https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-part-2-3p4m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vf95rask2k78gf52d7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vf95rask2k78gf52d7f.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-2pk2"&gt;Unlike Android&lt;/a&gt;, where libraries like OkHttp abstract much of the complexity, iOS takes a more low-level approach to networking and security.&lt;/p&gt;

&lt;p&gt;This means one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have more control — but also more responsibility.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this second part, we’ll explore how SSL pinning is implemented in iOS using two different strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Certificate Pinning (&lt;code&gt;.cer&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Public Key Pinning (recommended for production)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both approaches achieve the same goal — trusting only your backend — but they differ significantly in terms of stability, maintainability, and real-world viability.&lt;/p&gt;

&lt;p&gt;We’ll also take a step back and look at the bigger picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When pinning makes sense&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When it becomes a liability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And how it fits into a broader mobile security strategy&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  🍎 iOS Implementation
&lt;/h2&gt;

&lt;p&gt;iOS is more low-level. You’ll work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URLSession&lt;/li&gt;
&lt;li&gt;URLSessionDelegate&lt;/li&gt;
&lt;li&gt;Security.framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two approaches:&lt;/p&gt;




&lt;h2&gt;
  
  
  🟢 Approach 1: Certificate Pinning with .cer
&lt;/h2&gt;

&lt;p&gt;This is typically the first approach developers encounter when implementing pinning on iOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Export your backend certificate as .cer&lt;/li&gt;
&lt;li&gt;Add it to your Xcode project&lt;/li&gt;
&lt;li&gt;Compare it at runtime&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  🧪 Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;PinningDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;URLSessionDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;urlSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;didReceive&lt;/span&gt; &lt;span class="nv"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URLAuthenticationChallenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nv"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;AuthChallengeDisposition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;URLCredential&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protectionSpace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authenticationMethod&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;NSURLAuthenticationMethodServerTrust&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;serverTrust&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;protectionSpace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serverTrust&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;serverCertificate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SecTrustGetCertificateAtIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverTrust&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancelAuthenticationChallenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;serverCertData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SecCertificateCopyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverCertificate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;

        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;localCertPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forResource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"cer"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;localCertData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;contentsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fileURLWithPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;localCertPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancelAuthenticationChallenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;serverCertData&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;localCertData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useCredential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;URLCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serverTrust&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancelAuthenticationChallenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ⚠️ Downside (critical)
&lt;/h3&gt;

&lt;p&gt;This approach is:&lt;/p&gt;

&lt;p&gt;💣 Fragile&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certificates expire&lt;/li&gt;
&lt;li&gt;Renewal changes .cer&lt;/li&gt;
&lt;li&gt;Your app breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 You must release a new version of the app&lt;/p&gt;




&lt;h2&gt;
  
  
  🟡 Approach 2: Public Key Pinning (Recommended)
&lt;/h2&gt;

&lt;p&gt;Instead of comparing full certificates:&lt;/p&gt;

&lt;p&gt;👉 Compare public keys&lt;/p&gt;

&lt;p&gt;✔️ Advantages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Survives certificate renewal&lt;/li&gt;
&lt;li&gt;More stable in production&lt;/li&gt;
&lt;li&gt;Equivalent to Android approach&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🧪 Conceptual Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;serverPublicKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SecCertificateCopyKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serverCertificate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;localPublicKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SecCertificateCopyKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localCertificate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Compare keys or their hashes&lt;/span&gt;
&lt;span class="c1"&gt;// ⚠️ Apple APIs here are verbose and require careful handling.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧭 Better Option: Use a Library
&lt;/h3&gt;

&lt;p&gt;Instead of manual implementation, use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alamofire (widely used networking library)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;evaluators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ServerTrustEvaluating&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"api.yourservice.com"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PinnedCertificatesTrustEvaluator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ServerTrustManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;evaluators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;evaluators&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;serverTrustManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔍 What SSL Pinning DOES NOT Do
&lt;/h3&gt;

&lt;p&gt;Let’s be clear:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Covered by Pinning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt traffic&lt;/td&gt;
&lt;td&gt;✔ (via TLS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prevent MITM&lt;/td&gt;
&lt;td&gt;✔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authenticate user&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protect API access&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace VPN&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;👉 You still need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT / OAuth&lt;/li&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Backend security&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ⚠️ Real-World Trade-offs
&lt;/h3&gt;

&lt;p&gt;Before adding pinning, ask yourself:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❗ Operational cost&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certificate rotation becomes risky&lt;/li&gt;
&lt;li&gt;You need fallback pins&lt;/li&gt;
&lt;li&gt;You need monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❗ Release dependency&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A backend change can break clients instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❗ Debugging complexity&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Harder to inspect traffic (Charles Proxy, etc.)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧠 When Should You Use It?
&lt;/h3&gt;

&lt;p&gt;Use pinning if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You build fintech / healthcare apps&lt;/li&gt;
&lt;li&gt;You operate in hostile network environments&lt;/li&gt;
&lt;li&gt;You have strong DevOps practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid (or delay) if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’re building a typical consumer app&lt;/li&gt;
&lt;li&gt;You don’t control backend infrastructure&lt;/li&gt;
&lt;li&gt;Your team lacks experience with cert rotation&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧩 Recommended Architecture (No VPN)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mobile App
   ↓
HTTPS (TLS)
   ↓
API Gateway
   ↓
Authentication (JWT / OAuth)
   ↓
Microservices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional hardening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Certificate Pinning 🔐&lt;/li&gt;
&lt;li&gt;WAF 🛡️&lt;/li&gt;
&lt;li&gt;Rate limiting 🚦&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧠 Final Thoughts
&lt;/h3&gt;

&lt;p&gt;“SSL pinning” is often mentioned casually, but:&lt;/p&gt;

&lt;p&gt;👉 It’s not a silver bullet&lt;br&gt;
👉 It’s not a replacement for authentication&lt;br&gt;
👉 It’s not trivial to maintain&lt;/p&gt;

&lt;p&gt;Used correctly, it adds a strong extra layer of defense.&lt;/p&gt;

&lt;p&gt;Used blindly, it becomes a production risk.&lt;/p&gt;




&lt;h3&gt;
  
  
  👋 Closing
&lt;/h3&gt;

&lt;p&gt;If you’re working with Kotlin Multiplatform or shared logic, keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinning is platform-specific&lt;/li&gt;
&lt;li&gt;You’ll need separate implementations for Android and iOS&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ios</category>
      <category>mobile</category>
      <category>networking</category>
      <category>security</category>
    </item>
    <item>
      <title>🔐 SSL Pinning in Mobile Apps: Android &amp; iOS (Practical Guide + Trade-offs) - Part 1</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 04 May 2026 21:20:13 +0000</pubDate>
      <link>https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-2pk2</link>
      <guid>https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-2pk2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6cehy4m4u9cj6qp2lnj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6cehy4m4u9cj6qp2lnj.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When building mobile apps that consume APIs over the internet, HTTPS is &lt;strong&gt;mandatory&lt;/strong&gt;—but sometimes it’s not enough.&lt;/p&gt;

&lt;p&gt;If your app handles sensitive data (finance, health, enterprise), you might want to go one step further:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Certificate Pinning (aka “SSL pinning”)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What SSL pinning actually is (and what it isn’t)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to implement it in &lt;strong&gt;Android&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a second part, these topics will be covered: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How to implement it in &lt;strong&gt;iOS&lt;/strong&gt; (both &lt;code&gt;.cer&lt;/code&gt; and Public Key approaches)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The real trade-offs nobody tells you&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 What is SSL Pinning (really)?
&lt;/h2&gt;

&lt;p&gt;Despite the name, modern apps use &lt;strong&gt;TLS&lt;/strong&gt;, not SSL.&lt;/p&gt;

&lt;p&gt;👉 The correct term is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Certificate Pinning&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or &lt;strong&gt;TLS Pinning&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But “SSL pinning” is still widely used.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔐 Default HTTPS behavior
&lt;/h3&gt;

&lt;p&gt;By default, your app trusts &lt;strong&gt;any valid certificate&lt;/strong&gt; signed by trusted Certificate Authorities (CAs).&lt;/p&gt;

&lt;p&gt;That means:&lt;br&gt;
App → HTTPS → Server (valid cert) → OK&lt;/p&gt;
&lt;h3&gt;
  
  
  🚨 The problem
&lt;/h3&gt;

&lt;p&gt;If an attacker installs a malicious certificate (e.g. on public WiFi), they could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intercept traffic&lt;/li&gt;
&lt;li&gt;Decrypt requests&lt;/li&gt;
&lt;li&gt;Act as a proxy (MITM attack)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🔐 What Pinning Changes
&lt;/h2&gt;

&lt;p&gt;Instead of trusting all valid certs:&lt;/p&gt;

&lt;p&gt;👉 Your app trusts &lt;strong&gt;only a specific certificate or public key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If it doesn’t match → ❌ connection rejected&lt;/p&gt;



&lt;p&gt;In Android, SSL pinning can be implemented either at the HTTP client level (e.g., OkHttp) or at the platform level using Network Security Config.&lt;/p&gt;
&lt;h2&gt;
  
  
  📱 Android Implementation (OkHttp)
&lt;/h2&gt;

&lt;p&gt;Android makes this relatively straightforward thanks to OkHttp.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✔️ Public Key Pinning (recommended)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;certificatePinner&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CertificatePinner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api.yourservice.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sha256/AAAAAAAAAAAAAAAAAAAA..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;certificatePinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certificatePinner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  🧪 How to get the SHA-256 hash
&lt;/h3&gt;

&lt;p&gt;You can extract it using OpenSSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; api.yourservice.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; api.yourservice.com &lt;span class="se"&gt;\&lt;/span&gt;
  | openssl x509 &lt;span class="nt"&gt;-pubkey&lt;/span&gt; &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | openssl pkey &lt;span class="nt"&gt;-pubin&lt;/span&gt; &lt;span class="nt"&gt;-outform&lt;/span&gt; der &lt;span class="se"&gt;\&lt;/span&gt;
  | openssl dgst &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-binary&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | openssl enc &lt;span class="nt"&gt;-base64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧭 Alternative on Android: Network Security Config (Platform-Level Pinning)
&lt;/h2&gt;

&lt;p&gt;So far, we’ve implemented SSL pinning using OkHttp, which gives us fine-grained control at the HTTP client level.&lt;/p&gt;

&lt;p&gt;However, Android also provides a &lt;strong&gt;platform-level approach&lt;/strong&gt;: &lt;code&gt;Network Security Config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of configuring pinning in code, you can declare it in XML and apply it globally to your app.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔧 Example Configuration
&lt;/h3&gt;

&lt;p&gt;Create a file under:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;res/xml/network_security_config.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;network-security-config&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;domain-config&lt;/span&gt; &lt;span class="na"&gt;cleartextTrafficPermitted=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;domain&lt;/span&gt; &lt;span class="na"&gt;includeSubdomains=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;api.yourservice.com&lt;span class="nt"&gt;&amp;lt;/domain&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;pin-set&lt;/span&gt; &lt;span class="na"&gt;expiration=&lt;/span&gt;&lt;span class="s"&gt;"2026-05-09"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;pin&lt;/span&gt; &lt;span class="na"&gt;digest=&lt;/span&gt;&lt;span class="s"&gt;"SHA-256"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;YOUR_BASE64_SHA256_PIN&lt;span class="nt"&gt;&amp;lt;/pin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/pin-set&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/domain-config&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/network-security-config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reference it in your AndroidManifest.xml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
    &lt;span class="na"&gt;android:networkSecurityConfig=&lt;/span&gt;&lt;span class="s"&gt;"@xml/network_security_config"&lt;/span&gt;
    &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;🧠 How It Works&lt;/p&gt;

&lt;p&gt;This configuration tells Android:&lt;/p&gt;

&lt;p&gt;Only trust connections to this domain if the server’s certificate matches the pinned public key.&lt;/p&gt;

&lt;p&gt;Unlike OkHttp’s CertificatePinner, this operates at the platform level, not just within a specific HTTP client.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⚖️ OkHttp vs Network Security Config
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;Flexibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OkHttp CertificatePinner&lt;/td&gt;
&lt;td&gt;Per client&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network Security Config&lt;/td&gt;
&lt;td&gt;App-wide&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  ⚠️ Trade-offs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Still subject to certificate rotation issues&lt;/li&gt;
&lt;li&gt;Less dynamic than code-based approaches&lt;/li&gt;
&lt;li&gt;Android-only (no equivalent in iOS)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧭 When Should You Use It?
&lt;/h3&gt;

&lt;p&gt;Use Network Security Config when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want a centralized security policy&lt;/li&gt;
&lt;li&gt;Your app uses multiple networking libraries&lt;/li&gt;
&lt;li&gt;You prefer a declarative approach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use OkHttp pinning when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need fine-grained control&lt;/li&gt;
&lt;li&gt;You want to scope pinning to specific requests or clients&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🧠 Key Insight&lt;/p&gt;

&lt;p&gt;Both approaches ultimately solve the same problem:&lt;/p&gt;

&lt;p&gt;Restricting trust to a known certificate or public key.&lt;/p&gt;

&lt;p&gt;The difference lies in where the responsibility lives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your networking layer (OkHttp)&lt;/li&gt;
&lt;li&gt;Or in the Android platform configuration&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up (Part 1)
&lt;/h2&gt;

&lt;p&gt;At this point, we’ve covered what SSL pinning really is, what problems it solves (and what it doesn’t), and how to implement it on Android using a modern, production-ready approach.&lt;/p&gt;

&lt;p&gt;If there’s one takeaway from this first part, it’s this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pinning is not about replacing your security model — it’s about strengthening the transport layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On Android, the ecosystem makes it relatively straightforward to adopt public key pinning with tools like OkHttp. However, the real challenge isn’t implementation — it’s &lt;strong&gt;operational discipline&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handling certificate rotation&lt;/li&gt;
&lt;li&gt;Avoiding hard failures in production&lt;/li&gt;
&lt;li&gt;Understanding when pinning actually adds value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before moving forward, ask yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do I really need pinning, or am I trying to compensate for missing backend security?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://dev.to/devpicon/ssl-pinning-in-mobile-apps-android-ios-practical-guide-trade-offs-part-2-3p4m"&gt;In the next part&lt;/a&gt;, we’ll move to iOS — where things are a bit more low-level, and where the trade-offs become even more evident.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>android</category>
      <category>security</category>
      <category>networking</category>
    </item>
    <item>
      <title>Gemma 4 E2B on Mobile: Android vs iOS Reality (1)</title>
      <dc:creator>Armando Picón</dc:creator>
      <pubDate>Mon, 04 May 2026 19:53:30 +0000</pubDate>
      <link>https://dev.to/devpicon/gemma-4-e2b-on-mobile-android-vs-ios-reality-1-38lm</link>
      <guid>https://dev.to/devpicon/gemma-4-e2b-on-mobile-android-vs-ios-reality-1-38lm</guid>
      <description>&lt;p&gt;I'm still looking for a new job. In the meantime, I'm running experiments with the new Gemma 4 E2B model... &lt;/p&gt;

&lt;p&gt;I just wanted to share a few notes on this...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model uses the .litertlm extension, as it now relies on LiteRT-LM, the new framework to run these models in edge devices. It's an evolution of TensorFlow Lite.&lt;/li&gt;
&lt;li&gt;On Android,  there is a Kotlin-based API to run these models on Android devices optimized for coroutines.&lt;/li&gt;
&lt;li&gt;On iOS, there is currently no native Swift API to run it, so you have to rely on the C++ API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, one of my experiments consists of evaluating whether it's possible to run this model in a device without a dedicated IA chipset.&lt;/p&gt;

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

</description>
      <category>ai</category>
      <category>mobile</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <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://dev.to/devpicon/ios-cocoapods-cheatsheet-3j5b</link>
      <guid>https://dev.to/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://dev.to/devpicon/scalable-dependency-management-with-version-catalog-47lj</link>
      <guid>https://dev.to/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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje05000htzcgzulteiwa.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje05000htzcgzulteiwa.jpeg" alt=" " width="213" height="125"&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://dev.to/devpicon/android-desmitificando-clean-architecture-33m6</link>
      <guid>https://dev.to/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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdadpc22gfbugpf3pmd17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdadpc22gfbugpf3pmd17.png" alt=" " width="800" height="450"&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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccepm0me3tm77wsfltwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccepm0me3tm77wsfltwp.png" alt=" " width="800" height="450"&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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96jyttwblu32zd88ru05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96jyttwblu32zd88ru05.png" alt=" " width="800" height="450"&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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgboebcmfhsy7uuprzhjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgboebcmfhsy7uuprzhjg.png" alt=" " width="800" height="450"&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://dev.to/devpicon/kotlin-scoped-functions-let-with-run-apply-also-dhp</link>
      <guid>https://dev.to/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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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://dev.to/devpicon/que-nos-dejo-el-2020-y-que-nos-traera-el-2021-2kgp</link>
      <guid>https://dev.to/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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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://dev.to/devpicon/kotlin-coroutines-101-jobs-1d33</link>
      <guid>https://dev.to/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://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flofz6nb82txfo6w14ju2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flofz6nb82txfo6w14ju2.png" 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 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://dev.to/devpicon/kotlin-coroutines-on-android-101-1ij</link>
      <guid>https://dev.to/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://dev.to/devpicon/mi-nuevo-proyecto-codalot-podcast-1lnj</link>
      <guid>https://dev.to/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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&gt;Spotify for Podcasters&lt;/a&gt;, &lt;a href="https://podcastsconnect.apple.com/" rel="noopener noreferrer"&gt;Podcast Connect by Apple&lt;/a&gt;, &lt;a href="https://play.google.com/music/podcasts/portal/#p:id=playpodcast/all-podcasts" rel="noopener noreferrer"&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/" rel="noopener noreferrer"&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/" rel="noopener noreferrer"&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/" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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" rel="noopener noreferrer"&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>
  </channel>
</rss>
