<?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: Erik Henrique</title>
    <description>The latest articles on DEV Community by Erik Henrique (@erikunha).</description>
    <link>https://dev.to/erikunha</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%2F592044%2F83362f89-4c93-47bf-8fd1-5e8b840fc791.jpeg</url>
      <title>DEV Community: Erik Henrique</title>
      <link>https://dev.to/erikunha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erikunha"/>
    <language>en</language>
    <item>
      <title>Creating Type-Safe Forms in Angular: Advanced Tip 🤯</title>
      <dc:creator>Erik Henrique</dc:creator>
      <pubDate>Fri, 11 Aug 2023 16:11:55 +0000</pubDate>
      <link>https://dev.to/erikunha/creating-type-safe-forms-in-angular-advanced-tip-3b5l</link>
      <guid>https://dev.to/erikunha/creating-type-safe-forms-in-angular-advanced-tip-3b5l</guid>
      <description>&lt;p&gt;When developing complex applications in Angular, one common challenge is dealing with forms and their validation. As applications grow, so does the complexity of forms, leading to potential errors and maintenance difficulties. To address these challenges, Angular provides a powerful form handling module, &lt;code&gt;@angular/forms&lt;/code&gt;, which allows developers to create dynamic and type-safe forms. In this tutorial, we will explore a helpful utility type created by me called &lt;code&gt;WithControlsFrom&lt;/code&gt; that enhances the form-building process by providing type-safe controls for form fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to &lt;code&gt;WithControlsFrom&lt;/code&gt; type
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;WithControlsFrom&lt;/code&gt; type is a versatile utility that assists in creating type-safe forms using the &lt;code&gt;@angular/forms&lt;/code&gt; module. It simplifies the process of binding form controls to an interface, ensuring that the form's structure aligns with the interface properties. This utility type generates a type that defines each property of the interface as an optional form control. This way, you can avoid common errors like assigning an incorrect data type to a form control or referencing a non-existing property.&lt;/p&gt;

&lt;p&gt;Let's dive into an example to see how &lt;code&gt;WithControlsFrom&lt;/code&gt; can be used effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: &lt;code&gt;UserModel&lt;/code&gt; Form
&lt;/h2&gt;

&lt;p&gt;Suppose we have an interface &lt;code&gt;UserModel&lt;/code&gt; representing user data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to create a form for capturing user information using the &lt;code&gt;@angular/forms&lt;/code&gt; module. Here's how we can utilize the &lt;code&gt;WithControlsFrom&lt;/code&gt; type to achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 👇 This bind any interface with the FormGroup generating a type-safe form matching existing keys and FormControl type 🙂&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;WithControlsFrom&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FormArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-user-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;form [formGroup]="userForm"&amp;gt;
      &amp;lt;label&amp;gt;
        ID:
        &amp;lt;input type="number" formControlName="id" /&amp;gt;
      &amp;lt;/label&amp;gt;
      &amp;lt;label&amp;gt;
        Name:
        &amp;lt;input type="text" formControlName="name" /&amp;gt;
      &amp;lt;/label&amp;gt;
      &amp;lt;label&amp;gt;
        Gender:
        &amp;lt;input type="text" formControlName="gender" /&amp;gt;
      &amp;lt;/label&amp;gt;
    &amp;lt;/form&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFormComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;userForm&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormGroup&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WithControlsFrom&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserModel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WithControlsFrom&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserModel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;control&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;control&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Father Horse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;control&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;777&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Throws: Type 'FormControl&amp;lt;number&amp;gt;' is not assignable to type 'FormControl&amp;lt;string&amp;gt;'. Type 'number' is not assignable to type 'string'.&lt;/span&gt;
      &lt;span class="na"&gt;xyz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_formBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;control&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Throws: Object literal may only specify known properties, and 'xyz' does not exist in type 'WithKeysFrom&amp;lt;UserModel&amp;gt;'.&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this example, we've created a &lt;code&gt;UserFormComponent&lt;/code&gt; that defines a form group named &lt;code&gt;userForm&lt;/code&gt;. The form group is constructed using the &lt;code&gt;WithControlsFrom&lt;/code&gt; type, which ensures that the form controls correspond to the properties of the &lt;code&gt;UserModel&lt;/code&gt; interface. Each property is mapped to a corresponding form control, and the form's HTML template uses the &lt;code&gt;formControlName&lt;/code&gt; directive to bind the form controls to the input elements.&lt;/p&gt;

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

&lt;p&gt;In this tutorial, we explored the &lt;code&gt;WithControlsFrom&lt;/code&gt; utility type, which greatly simplifies the process of creating type-safe forms in Angular applications. By leveraging this utility, developers can ensure that their form controls align with the structure of the underlying data model, reducing the risk of errors and improving code maintainability. This type-safe approach to form creation enhances the development experience and contributes to the overall robustness of Angular applications.&lt;/p&gt;

&lt;p&gt;For more information on working with forms in Angular, you can refer to the official Angular documentation.&lt;/p&gt;

&lt;p&gt;Remember that using &lt;code&gt;WithControlsFrom&lt;/code&gt; can significantly enhance the reliability and maintainability of your forms, ensuring that your code remains consistent with your data models. Happy coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://angular.io/guide/reactive-forms" rel="noopener noreferrer"&gt;Angular Forms Documentation ↩&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/docs/handbook/2/generics.html" rel="noopener noreferrer"&gt;TypeScript Generics ↩&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disclaimer
&lt;/h3&gt;

&lt;p&gt;This article was made with a little help from ChatGPT.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What are Progressive Web Apps (PWAs) 📱💡</title>
      <dc:creator>Erik Henrique</dc:creator>
      <pubDate>Wed, 27 Oct 2021 23:54:03 +0000</pubDate>
      <link>https://dev.to/erikunha/what-are-pwas-17k5</link>
      <guid>https://dev.to/erikunha/what-are-pwas-17k5</guid>
      <description>&lt;p&gt;The concept of PWAs (Progressive Web Apps) is not new. It has been around since 2015, when Google introduced this new form of web experience on mobile devices. In the past few years, PWAs have gained strength and more people are betting on this idea. But, what are PWAs exactly? A Progressive Web App is a web app that uses modern browser features to provide users with an experience similar to a native application. These apps are hosted on servers, accessible by URLs and indexed by search engines. According to Google, PWAs should be:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reliable
&lt;/h3&gt;

&lt;p&gt;When it is opened in a user’s home screen, a Progressive Web App loads instantly, regardless of the state of the network, and never shows the downasaur, even under uncertain network conditions. As the main features of the PWA are pre-stored in cache, it is able to eliminate dependency on the network, ensuring an instant and reliable experience for its users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast
&lt;/h3&gt;

&lt;p&gt;About 53% of users leave a website if it takes more than 3 seconds to load. Once they have loaded, users expect websites to be fast, without irregular scrolling or slow response in their interfaces. Most websites load all files and images (which are usually the heaviest) when accessed for the first time and this ends up impacting users’ experience, since they have to wait for the end of this process to start interacting with the website.&lt;br&gt;
For this reason, a PWA should not only open quickly when accessed, but should also have a short response time on its interfaces, to reduce what is called Time to Interactive (TTI), loading files and making calls to other resources and sources only when really necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engaging
&lt;/h3&gt;

&lt;p&gt;PWAs should make users feel like they are in a native app. Progressive Web Apps can be installed and stay on the user’s home screen, without the need for an app store. They offer an immersive, full-screen experience and can even re-engage users with Push Notifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the “Mobile App Era” ending?
&lt;/h3&gt;

&lt;p&gt;The mobile app boom that began in July 2008, when Apple launched the App Store, is no longer the same. Many companies know how difficult and costly it is to get people to download their apps. Have you ever stopped to think about how many apps from the App Store or Play Store you download each month?&lt;br&gt;
According to &lt;a href="https://s3.amazonaws.com/files.appannie.com/reports/1901_State_of_Mobile_Main_EN.pdf" rel="noopener noreferrer"&gt;The State of Mobile 2019&lt;/a&gt;, from App Annie, in terms of time of use, the most used apps in 2018 were communication and social networking apps, responsible for 50% of the time spent on apps globally. They were followed by video players and editors (15%) and games (10%). According to &lt;a href="https://www.statista.com/chart/3835/top-10-app-usage/" rel="noopener noreferrer"&gt;Statista&lt;/a&gt;, 96% of users’ time is spent on 10 applications. Of that 96%, most of the time is used in up to 3 apps.&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%2F4nbnvdg64f4aj85dc6gm.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%2F4nbnvdg64f4aj85dc6gm.png" alt="statista-top-10-app-usage" width="752" height="467"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://www.statista.com/chart/3835/top-10-app-usage/" rel="noopener noreferrer"&gt;https://www.statista.com/chart/3835/top-10-app-usage/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given this scenario, it becomes increasingly important to understand how users relate to apps, to identify aspects of user experience that can be improved, not only in the original apps themselves, but to make suggestions and to use in other options.&lt;/p&gt;

&lt;h3&gt;
  
  
  User retention
&lt;/h3&gt;

&lt;p&gt;Retention is a measure of the percentage of users who return to an app sometime after its purchase. For apps, retention is assessed by the number of users who continue to use an application, for example, one, two or three months after its download. Turnover is the opposite, measuring the percentage of people who do not return to a product or service after a certain period of time, migrating to other options in the market.&lt;br&gt;
According to data from &lt;a href="https://www.localytics.com/lp/cheat-sheet-overall-app-benchmarks-h2-2018/" rel="noopener noreferrer"&gt;Localytics&lt;/a&gt;, 43% of users continue using apps a month after downloading them, which means that 29% of users generate turnover and are no longer using those apps after a month. Things get worse as time goes by, reaching an average of 71% churning rate in the 3rd month.&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%2Fusyhc4t3saks81tvsep4.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%2Fusyhc4t3saks81tvsep4.png" alt="cheat-sheet-overall-app-benchmarks-h2-2018" width="704" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://www.localytics.com/lp/cheat-sheet-overall-app-benchmarks-h2-2018/" rel="noopener noreferrer"&gt;https://www.localytics.com/lp/cheat-sheet-overall-app-benchmarks-h2-2018/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retention can also be more thorough, being measured by how many users return to an app in a specific number of days after its download. About 24.9% of users revisit apps one day after downloading them, while only 9.4% of users revisit apps two weeks after their download.&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%2Fv7izjdkj7oogpvoqnt8w.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%2Fv7izjdkj7oogpvoqnt8w.png" alt="User leaving app graph" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://www.localytics.com/lp/cheat-sheet-overall-app-benchmarks-h2-2018/" rel="noopener noreferrer"&gt;https://www.localytics.com/lp/cheat-sheet-overall-app-benchmarks-h2-2018/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, just having an app in stores does not mean that people will use it or even download it. In the world of native apps — in which large user bases, traffic, among other points, are necessary for monetization — however wonderful a new application idea may be, it costs more and more advertising and promotion to reach a critical mass and generate revenue efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between developing a native app and a PWA?
&lt;/h3&gt;

&lt;p&gt;Building native apps can be a very expensive solution for some companies, as it requires the maintenance of two software development teams, one for Android and the other for iOS. As it is necessary to ensure that both versions of the app are up to date, developing new features can greatly impact the productivity of a team or a company.&lt;/p&gt;

&lt;p&gt;Since all that is needed in order to develop a PWA are web technologies, there is no need for multiple teams with expertise in different operating systems. For iOS apps, it is still necessary to go through Apple’s review with each new version. On the other hand, a PWA is hosted on a server and accessed through an address in the browsers bar. Therefore, it doesn’t need Apple’s approval and doesn’t have to have its new versions sent to app stores.&lt;/p&gt;

&lt;p&gt;On Android, Google’s Play Store already supports the publication of PWAs, which brings many benefits and makes users’ experience better, as if they were using a real installed app.&lt;/p&gt;

&lt;p&gt;Thus, for the development of PWAs, it is only necessary to have knowledge in web technologies (there are several options between frameworks and libraries) to serve users of practically all platforms, without having to be an expert in each user’s preferred operating system.&lt;/p&gt;

&lt;p&gt;Another important aspect to be considered when developing apps and PWAs is the space needed to install them on a hard drive. A growing trend are cloud-based services and Software as a Service (SaaS) models delivered by browsers instead of installed software. Today, we already have many well-established SaaS, such as Netflix and Spotify, which also serve app users. However, the idea of a SaaS is that all that is needed for the experience is an Internet connection.&lt;/p&gt;

&lt;p&gt;The aim of a SaaS is to be able to be accessed from any device, anywhere. This concept is very similar to the principles and characteristics of PWAs. As PWAs are an option that considers both the reduction of space on the hard disk needed for an app, the reduction of data needed for it to work, and also have offline versions that make them less dependent on an internet network, they can be a means to achieve a SaaS that is even more accessible and independent.&lt;/p&gt;

&lt;h4&gt;
  
  
  Checklist
&lt;/h4&gt;

&lt;p&gt;There is a list of items and features created by Google that define what is expected of a PWA:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Progressive&lt;/strong&gt;: made for any user, regardless of their preferred browser;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive&lt;/strong&gt;: made for any device (desktop, tablet or mobile);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connectivity-independent&lt;/strong&gt;: works even if the user is offline;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-like&lt;/strong&gt;: the user should feel as if they are in a native app;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fresh&lt;/strong&gt;: no need to download updates from the application, the browser will simply detect a new version and update it automatically if necessary;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe&lt;/strong&gt;: done only with HTTPS (Hyper Text Transfer Protocol Secure), seeking to ensure that the domain or address is verified;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-engeable&lt;/strong&gt;: through Push Notifications, the user can be constantly engaged;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installable&lt;/strong&gt;: an icon can be added to the main work area of a smartphone and desktop with just one click;
Thus, while there are many things that can lead a baseline PWA to a good experience, the &lt;a href="https://web.dev/pwa-checklist/#baseline" rel="noopener noreferrer"&gt;checklist&lt;/a&gt; provided by Google can help teams to create the best possible experiences for users. The list includes, according to them, all the things that are needed for a baseline PWA and how to take it a step further and provide fantastic usability by thinking about users, the (often limited) conditions they may have and not the platform itself.
One tool that can help a lot during the development of PWAs is &lt;a href="https://developers.google.com/web/tools/lighthouse?hl=pt-br" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt;, also created by Google. Initially, the tool was designed to audit PWAs, but its main goal is to assist in improving all aspects of a Web App. It can be run via terminal or installed in Chrome as an extension. The tool applies tests to a website, offering tips, suggestions and possible solutions in 5 different aspcts: Performance, Accessibility, Best Practices, SEO (Search Engine Optimization) and PWA.&lt;/li&gt;
&lt;/ol&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%2Fx7l801a0401k6e9oa3tl.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%2Fx7l801a0401k6e9oa3tl.png" alt="Lighthouse example" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These 5 different categories in Lighthouse seek to identify, according to metrics studied by Google, what are the scores of a website or PWA according to these studies. This directly impacts the ranking or position of the site when a user searches on Google, because the search algorithm also takes this ranking into account.&lt;/p&gt;

&lt;h4&gt;
  
  
  Limitations with respect to native applications
&lt;/h4&gt;

&lt;p&gt;A downside to PWAs is that they do not yet have full control over the hardware of the device on which they are installed. Bluetooth, contact list and Near Field Communication (NFC) are some examples of features that can’t be accessed by PWAs yet (access &lt;a href="https://whatwebcando.today" rel="noopener noreferrer"&gt;https://whatwebcando.today&lt;/a&gt; to see more limitations).&lt;/p&gt;

&lt;p&gt;Another point is that while Google, Microsoft and Mozilla are betting high on this new approach, Apple is not focused on it yet. In iOS 11.3 of Apple’s mobile operating system, support has been added to the basic set of new technologies behind the idea of Progressive Web Apps (see more here &lt;a href="https://firt.dev/notes/pwa-ios/" rel="noopener noreferrer"&gt;https://firt.dev/notes/pwa-ios/&lt;/a&gt;). However, there is still a lot to be implemented and corrected to provide the user experience that is expected from a real PWA. Apple doesn’t seem to be in a hurry to implement full support for these apps — for example, one of the basic points that isn’t yet supported on iOS, but not mandatory in the PWAs, is the option of sending Push Notifications. Still, even if Apple doesn’t fully adopt PWAs, they’re already a reality and are all around us with remarkable results, some examples of which we’ll explore next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case Studies
&lt;/h3&gt;

&lt;p&gt;Below, we can see some of the big companies in the world that have already adopted PWAs and the results they have brought to these companies:&lt;/p&gt;

&lt;h4&gt;
  
  
  Tinder
&lt;/h4&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%2Fw8s1vvqjgizt8orjs2pn.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%2Fw8s1vvqjgizt8orjs2pn.png" alt="Tinder" width="371" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;URL:&lt;a href="https://tinder.com/?lang=pt-BR" rel="noopener noreferrer"&gt;https://tinder.com/?lang=pt-BR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tinder.com/?lang=pt-BR" rel="noopener noreferrer"&gt;Tinder PWA&lt;/a&gt;, the relationship app, developed its own PWA in about 3 months. While the Tinder Android app requires 30 MB of space, its PWA version offers the main Tinder experience at a data cost of 2.8 MB. The PWA also appears to encourage more activity from users. Compared to users of the native app, PWA users swipe more, send more messages and use the app for longer periods of time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Uber
&lt;/h4&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%2F0r0l33sdd0t4xa9sdsqh.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%2F0r0l33sdd0t4xa9sdsqh.png" alt="Uber PWA" width="358" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;URL: &lt;a href="https://m.uber.com" rel="noopener noreferrer"&gt;https://m.uber.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://m.uber.com" rel="noopener noreferrer"&gt;Uber&lt;/a&gt; needed an app that could be used by anyone, regardless of the speed of their network or device. Its solution was to develop a PWA that mimics its native features in functionality, but that had a significantly smaller MB size of stored data. Using small libraries and SVGs (Scalable Vector Graphics) instead of images where possible, Uber‘s Progressive Web App is just 50 KB and loads in less than three seconds even on 2G networks!&lt;/p&gt;

&lt;h4&gt;
  
  
  Twitter
&lt;/h4&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%2F6x03ts7gi0ysvf9iz2gn.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%2F6x03ts7gi0ysvf9iz2gn.png" alt="Twitter PWA" width="358" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;URL: &lt;a href="https://mobile.twitter.com/" rel="noopener noreferrer"&gt;https://mobile.twitter.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although smartphone adoption had grown to 3.8 billion connections by the end of 2016, 45% of mobile connections are still on slower 2G networks, according to the GSMA (Global System for Mobile Communications Association), a trade body that represents the interests of mobile network operators worldwide. With Twitter Lite — the PWA version of Twitter, a social networking app — it is possible to preview images and videos before choosing which ones to upload fully. This reduces data usage by up to 70%, turning Twitter more accessible in areas where mobile data is expensive.&lt;/p&gt;

&lt;h4&gt;
  
  
  iFood
&lt;/h4&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%2Ftxa6k9khbassgua7n07z.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%2Ftxa6k9khbassgua7n07z.png" alt="Ifood PWA" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;URL: &lt;a href="https://www.ifood.com.br/pwa" rel="noopener noreferrer"&gt;https://www.ifood.com.br/pwa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ifood.com.br/pwa" rel="noopener noreferrer"&gt;iFood&lt;/a&gt;, a Brazilian food delivery app, also recently launched its PWA. This version occupies only 280 KB on Android, but does not include notifications about the status of orders and coupons — although the iFood team is already working on it, according to the app.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>mobile</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
