<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Brent Dalling</title>
    <description>The latest articles on Forem by Brent Dalling (@brentdalling).</description>
    <link>https://forem.com/brentdalling</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%2F626708%2Fa16afab0-e0b2-4e09-a357-d8a7ff14fd36.png</url>
      <title>Forem: Brent Dalling</title>
      <link>https://forem.com/brentdalling</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brentdalling"/>
    <language>en</language>
    <item>
      <title>JWT's for authentication</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Fri, 24 Feb 2023 19:37:25 +0000</pubDate>
      <link>https://forem.com/brentdalling/jwts-for-authentication-21fe</link>
      <guid>https://forem.com/brentdalling/jwts-for-authentication-21fe</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Hi there! I'm Brent. I'm a senior software developer with 8 years of professional experience. I've written software professionally in Java, JS/TS, PHP, C#, Python, Swift, Obj_C, Vue, React, Laravel, CodeIgniter, Ionic, SwiftUI, and many more languages or frameworks. I'm learning more every day. Just like you! My articles explain my thought process, opinions, and outlook. They're not the views of my employer. Just my own. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  JWT's for authentication
&lt;/h4&gt;

&lt;p&gt;It's a relatively common question. But, let's back up for a moment. Since the early days of computing we've needed some sort of user authentication and role/permission management. Early forms of this used local storage on hard-disks. &lt;/p&gt;

&lt;h4&gt;
  
  
  State-ful Sessions
&lt;/h4&gt;

&lt;p&gt;As networking evolved, and peer-to-peer networking emerged, we started needing access to resources not stored on our local hard disk. These resources also needed some sort of authentication. Thus, the concept of remote authentication and user sessions was born. &lt;/p&gt;

&lt;p&gt;Remote authentication needed to make sure that user sessions were secure, revocable, and relatively friction-less. For years, frameworks like .NET, Laravel, CodeIgniter, and basic language built features like the PHP Session used local storage to place a session file. This file would be used to verify a session cookie claim and find session information related to the user. (see sources - Advanced PHP Sessions) These sessions would send a cookie with the sessionId name and the client-side would send this sessionId cookie back to the server with every request.&lt;/p&gt;

&lt;p&gt;When a request was made to the server the sessionId would be looked up and verified. This process slows down server responses potentially as it has to look linearly through the file system until it find a file with the sessionId as the name. Once it found the file it would perform some sort of validation. Additionally, once the session was verified, the session would be loaded into a variable with access to all session attributes. This is how the PHP session works. This isn't necessarily how all sessions work across all languages and frameworks. &lt;/p&gt;

&lt;h4&gt;
  
  
  Enter JWT and state-less sessions
&lt;/h4&gt;

&lt;p&gt;JWT's are very similar to the traditional session method. Except, instead of keeping a copy of the JWT on the server, the server would send the JWT to the front-end and require that the front-end passes the JWT to the server for each request. (this is much like the session cookie with PHP type sessions). The server then verifies the signature (part of the JWT structure. We will discuss this later.) and guarantees that the contents are valid. This can potentially reduce server load. Admittedly, not by much as the hashing can be performance intensive.&lt;/p&gt;

&lt;p&gt;The JWT's are a signed state-less token that have three parts to them. The header, the payload, and the signature. The header contains information about how the token was hashed. The body contains encoded claims. The signature is the signed claims and header. Because the JWT is signed and is capable of being verified on the server it is capable of being a form of state-less session. This simply means that the server doesn't maintain this information between requests. Instead, the server decodes the JWT for every request and assigns/permits operations based on the contained claims.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJ1c2VyIjp7ImZpcnN0X25hbWUiOiJCcmVudCIsImxhc3RfbmFtZSI6I
kRhbGxpbmciLCJwcm9maWxlIjp7ImF2YXRhciI6Imh0dHBzOi8vLi4uLiIs
ImdpdGh1YiI6Imh0dHBzOi8vLi4uLiJ9LCJyb2xlIjoiYWRtaW4iLCJwZXJ
taXNzaW9ucyI6eyJjYW4tcmVhZC11c2VycyI6dHJ1ZSwiY2FuLXVwZGF0ZS1
1c2VycyI6ZmFsc2UsImNhbi1kZWxldGUtdXNlcnMiOmZhbHNlLCJjYW4tY3
JlYXRlLXVzZXJzIjpmYWxzZSwiY2FuLXNlbmQtbWVzc2FnZXMiOnRydWV9fX0
.1npfC1UPIIQRHj8aj_flqRU9IchB30Sc8WpGiRnoCms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Line breaks added for readability&lt;/p&gt;

&lt;p&gt;The JWT above contains all three sections. The header, body, and signature. The header contains information on the hashing algorithm. The body is the long middle section spanning several lines. The signature is the last section. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;JWt's have public and private claims inside the body. Public claims correspond to the reserved keys. We'll not be talking about these as most developers won't be using them. &lt;em&gt;(The sources for this article will contain the "JWT Handbook" which talks about this more in-depth.)&lt;/em&gt; Private claims are any claim that you add in a ad-hoc basis. These claims usually contain information about the service, user, and anything else you need your client-side to know about. You can usually find private claims like below contained in the body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Brent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dalling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://...."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://...."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can-read-users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can-update-users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can-delete-users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can-create-users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can-send-messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the above example contains absolutely no sensitive information. This is because the JWT itself can be considered insecure and the contents transparent. This is because of the JWT header. Remember, this is because the JWT header contains information on the hashing. This is a JWT requirement so that the token consumers can decode it and view the contents. This means that anyone can intercept or scrape these tokens and view the contents of them. &lt;/p&gt;

&lt;p&gt;For this reason, JWT's should absolutely never contain sensitive information. Credit cards, social security numbers, drivers licenses, etc should never be exposed to the JWT. To do so would be to create massive Availability-based security issue.  (Please see both the JWT Handbook and the CIA-Triad)&lt;/p&gt;

&lt;p&gt;The JWT itself is secure. This is because the token is signed by a hashing algorithm using a private key on the server. This signed value is then stored as the signature. The last piece of the 3-part JWT. Only the server knows the key. And, therefore, the server is the only machine that can validate it. This isn't to say there are not ways around this. Of course there are. (please see JWT-Attacks for additional reading into advanced security issues with JWT's) But, from a developer and researcher point of view they are considered secure enough. They are secure enough that they are now baked into many frameworks, API's, and services. A JWT properly implemented has a low security risk.&lt;/p&gt;

&lt;p&gt;JWT's properly implemented have one major security vulnerability. The developer implementing the standard or packages. If the developer places sensitive information, and exposes any of the CIA_Triad, then the developer has introduced a major privacy vulnerability. For this reason, I recommend that junior developers have their implementation reviewed. &lt;/p&gt;

&lt;p&gt;In conclusion, JWT's are secure by nature. They provide a great state-less session standard. And, they're highly versatile and dependable. There's a reason the JWT has become a de-facto standard in client to server-side communications. It accomplishes the exact same goals as the old PHP session standards. But, it accomplishes this while removing the verification/lookup load from the server. I can recommend them when properly implemented. Happy coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Bibliography
&lt;/h3&gt;

&lt;p&gt;Advanced PHP Sessions: &lt;a href="https://canvas.seattlecentral.edu/courses/937693/pages/10-advanced-php-sessions" rel="noopener noreferrer"&gt;https://canvas.seattlecentral.edu/courses/937693/pages/10-advanced-php-sessions&lt;/a&gt;&lt;br&gt;
JWT Handbook: &lt;a href="https://auth0.com/resources/ebooks/jwt-handbook/" rel="noopener noreferrer"&gt;https://auth0.com/resources/ebooks/jwt-handbook/&lt;/a&gt;&lt;br&gt;
CIA-Triad: &lt;a href="https://www.techtarget.com/whatis/definition/Confidentiality-integrity-and-availability-CIA" rel="noopener noreferrer"&gt;https://www.techtarget.com/whatis/definition/Confidentiality-integrity-and-availability-CIA&lt;/a&gt;&lt;br&gt;
JWT-Attacks: &lt;a href="https://portswigger.net/web-security/jwt" rel="noopener noreferrer"&gt;https://portswigger.net/web-security/jwt&lt;/a&gt;&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Get good fast. Learn Design Patterns.</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate>
      <link>https://forem.com/brentdalling/skip-design-patterns-1g5n</link>
      <guid>https://forem.com/brentdalling/skip-design-patterns-1g5n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;disclaimer: This is an opinion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recently I've run into some situations on code-help servers or development communities that are easily solved by understanding some fundamental design patterns. Lacking this knowledge can lead to the infamous head-banging-on-desk situations. So, let's explore the purpose of design patterns, where they came from, why they're still used, and how you can learn them for free.&lt;/p&gt;

&lt;p&gt;Design patterns are development patterns that arose when developers found themselves trying to solve specific design problems. Specifically, they noticed some... wait for it... patterns. They realized the strategies they used to solve problems were applicable in more than one situation and solved pretty complex problems. By documenting these patterns they aimed to help other developers to overcome these technical challenges more easily and advance the career field. &lt;/p&gt;

&lt;p&gt;The first design patterns book was called "Design Patterns: Elements of Reusable Object-Oriented Software" and was written by four individuals since dubbed "The Gang of Four". Their book shaped software education and development since the publication. This book as been commonly used in university level educations and even read by the self-taught programmer. The concepts they discuss and the way the address, explain, and catalog each of the main 23 patterns was simple, straight to the point, and provided rich context to the patterns that reduced the need for developers to "self discover" the concepts. &lt;/p&gt;

&lt;p&gt;Consequently, the book the Gang of Four introduced has since helped developers of all levels to understand, troubleshoot, implement, and improve software systems using the base concepts provided in the book. There's no doubt these patterns have played an important role in the evolution of the software industry. &lt;/p&gt;

&lt;p&gt;In the age of meta frameworks, libraries, and partial solutions do you really need to learn it? It's 23 more concepts to learn, conceptualize, and apply before setting out on your software career after all. Can't you get by without learning these? The short answer: you don't need to learn it do write software. The most realistic answer: while you don't need it you will improve your ability to write clean, performant, and concise software by understanding the basics of code design patterns. &lt;/p&gt;

&lt;p&gt;Let's explore how these help you and why developers still choose to use them today. Let's imagine I was asked to create a two way communication system between two completely unrelated classes. To the junior developer this may be vexing. To the senior developer they'd just use callbacks or lambdas in most languages. That way they pass the data to where it needs to go. But, what if there's a more efficient way of handling this? &lt;/p&gt;

&lt;p&gt;Introducing one of the twenty-three concepts: the Observer Pattern. Instead of the class supplying data having to be aware of the callback and how to handle it you can use event based programing and simply register a callback to the class issuing the events. Then, when an event is fired on the observed class, the listener can do whatever it likes with the supplied data. In code we typically call this the pub/sub model and it's heavily used in the HTML DOM and JS.&lt;/p&gt;

&lt;p&gt;This pattern is also heavily used in communications between two systems. Such as when using websockets. The Observer registers to listen to a specific event on a socket. The Observer takes on the role of the subscriber and waits for the specific event to come down the pipe from the publisher (the observed). This model allows both systems (remote and local) to have no knowledge of one another or how to handle the callbacks / classes. This concept is a loose form decoupling. &lt;/p&gt;

&lt;p&gt;So we've established that these patterns are heavily used and we briefly examined one of the many patterns that developers see and use without really knowing what it is. So how do you learn these? Do you need to attend a university? Buy a 30 year old book for $40? Sell your kidney? Well, no. You can read about each of the patterns for free at any of the resources below. I seriously recommend reading at least some of them. And remember, all developers at every level of their career must continue their education to become more effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Free Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://refactoring.guru/design-patterns" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.freecodecamp.org/news/tag/design-patterns/" rel="noopener noreferrer"&gt;https://www.freecodecamp.org/news/tag/design-patterns/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Paid Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612" rel="noopener noreferrer"&gt;https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612&lt;/a&gt;&lt;br&gt;
&lt;a href="https://refactoring.guru/design-patterns/book" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/book&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you found this helpful please leave a like and bookmark. Please leave a comment! Let's discuss this topic! If you spotted a problem with the information provided please leave a comment and let me know. Let's have a healthy discussion! Thanks for reading!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>welcome</category>
    </item>
    <item>
      <title>Wait what? Intro to Decomp.</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Fri, 18 Nov 2022 16:03:04 +0000</pubDate>
      <link>https://forem.com/brentdalling/decomposition-aln</link>
      <guid>https://forem.com/brentdalling/decomposition-aln</guid>
      <description>&lt;p&gt;Hello there! You clicked the link to find out what this was about. Didn't you? A one word title? Crazy! This article is about requirement decomposition in project management.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Decomposition project management is a process of breaking a large, complex project into smaller, more manageable parts. This technique can be used to decompose a project into smaller tasks or to decompose a large product into smaller component parts.&lt;br&gt;
&lt;a href="https://monday.com/blog/project-management/decomposition-project-management/"&gt;https://monday.com/blog/project-management/decomposition-project-management/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Decomposition in project management is the practice of taking a requirement, feature, or outcome and then breaking it down into smaller and more actionable steps. Chances are that your project manager or senior engineers are already doing this. But, it is a skill that every developer needs. This post will walk through an example scenario and explain each step. You will have a more than basic understanding of decomposition in project management by the end of the post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A customer wants to build a micro-blogging platform entirely in Node. The platform should handle multiple authors, drafting, and scheduling posts. Login needs to be simple and secure. There needs to be view and like tracking. The platform should permit a simple comment system with no more than 1 level of comments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay. This seems simple enough. We've all built simple blog systems in the past while following sketchy YouTube tutorials with questionable code quality and explanations. We got this! But, we need to break down these features and requirements into more manageable steps. &lt;/p&gt;

&lt;p&gt;When approaching this request I would first ask "What is the base functionality?". The answer? Creating posts and displaying those posts to the end user. Okay. Now, what goes into making a post? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User can click "new post"&lt;/li&gt;
&lt;li&gt;User can write content.&lt;/li&gt;
&lt;li&gt;User can add images and videos&lt;/li&gt;
&lt;li&gt;User can click publish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay! Now we are talking! We have 4 steps that are actionable, manageable, and simple. Each of these can become a step in the SDLC (Software Development Life Cycle). Each of these steps has some sort of complexity that must be handled. But, we derived these steps from "making a post" as a requirement! &lt;/p&gt;

&lt;p&gt;Okay, so if we repeat this process for each of the remaining requirements we may get the following.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Permit author invite via dashboard&lt;/li&gt;
&lt;li&gt;Permit author registration invite code&lt;/li&gt;
&lt;li&gt;Permit author to CRUD their own information EXCEPT for their role&lt;/li&gt;
&lt;li&gt;Permit author to delete their own account and transfer their content to another author&lt;/li&gt;
&lt;li&gt;Permit an author to make updates or co-author a post&lt;/li&gt;
&lt;li&gt;Record all authors automatically who contribute to an article&lt;/li&gt;
&lt;li&gt;Permit original author to remove co-authors from article&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drafting / Scheduling / Publishing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Permit marking a post as [draft, scheduled, published]&lt;/li&gt;
&lt;li&gt;If post is "scheduled" then include a date/time field to specify when it should be published&lt;/li&gt;
&lt;li&gt;Do not show [draft, scheduled] posts to end users&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Login
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Depending on back-end (firebase? pocketbase? custom api?) wire up a simple login flow of: email/password or email / magic link&lt;/li&gt;
&lt;li&gt;Include 2fa methods of [sms/generator]&lt;/li&gt;
&lt;li&gt;Logout the user after 10 min of inactivity. But, save their post work before logout if they are currently editing a post.&lt;/li&gt;
&lt;li&gt;If user can't verify password after 3 attempts send an alert email to sysadmin and user then lock the account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  View and Like tracking
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;include some sort of async JS code to alert the back-end of a view lasting more than 5 seconds. Maybe include mouse tracking so we don't record bots or crawlers.&lt;/li&gt;
&lt;li&gt;include JS code to alert back-end of a like&lt;/li&gt;
&lt;li&gt;display views and likes in the admin dashboard&lt;/li&gt;
&lt;li&gt;display views and likes in the post itself&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comments
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;users can signup for a simple "user" role account which permits: [commenting, liking, saving posts]&lt;/li&gt;
&lt;li&gt;Comments include username, profilePic, content, createdAt, likeCount&lt;/li&gt;
&lt;li&gt;Comments can be liked&lt;/li&gt;
&lt;li&gt;Comments can be reported (this will require back-end code to handle the report)&lt;/li&gt;
&lt;li&gt;Comments can be shared (provide direct link to the comment)&lt;/li&gt;
&lt;li&gt;Comments will NOT support [images/videos, rich formatting, HTML]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;--&lt;br&gt;
And, just like that, we have a simple list of tasks from our request. However, there are still more actionable items to be found in here. Try to find the steps that I missed and include them in the comments. Let's practice the technique and find those missing steps. hint: every feature has a ton of back-end requirements or related requirements that are missing.&lt;/p&gt;

&lt;p&gt;If you liked this article please bookmark it, like it, and share it! I'll be writing more basics articles in the near future with interactive examples! &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>management</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Wordle Clone</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Thu, 10 Nov 2022 19:34:26 +0000</pubDate>
      <link>https://forem.com/brentdalling/wordle-clone-c48</link>
      <guid>https://forem.com/brentdalling/wordle-clone-c48</guid>
      <description>&lt;p&gt;I got bored during a non-work meeting last night and decided to build something fun. I don't know how I settled on ripping off wordle. But, here we are. Take a look and have some fun. You can copy it and add your own words if you want. &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/brentvdalling/embed/BaVWdYL?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Feel free to comment any suggestions or criticisms.&lt;/p&gt;

</description>
      <category>codepen</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Design Patterns: Adapter Pattern</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Wed, 09 Nov 2022 17:05:09 +0000</pubDate>
      <link>https://forem.com/brentdalling/jsts-adapter-pattern-g17</link>
      <guid>https://forem.com/brentdalling/jsts-adapter-pattern-g17</guid>
      <description>&lt;p&gt;Okay. Let's explore something together. I've recently come across a few open source projects that can really use this pattern / strategy.&lt;/p&gt;

&lt;p&gt;So hear me out. Code design patterns exist and are thoroughly documented and taught for a reason. They improve out efficiencies and code reliability. So, why don't more developers use them? I think the answer is because they're normally grouped with Data Structures and Algorithms in schools. Therefore they're thought of as scary. Or, self taught developers (like me) just don't know they exist until someone mentions them. &lt;/p&gt;

&lt;p&gt;I took about 3 years of being a developer to really start learning these concepts. Before then I was building custom software for an ISP. My code was clean. But it was not efficient. So, let's dive into one of my favorite patterns. The &lt;code&gt;Adapter Pattern&lt;/code&gt;. duh. dong. daaaaaaa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.&lt;br&gt;
&lt;a href="https://refactoring.guru/design-patterns/adapter"&gt;https://refactoring.guru/design-patterns/adapter&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay. So, it some how allows for two objects with completely different methods and attributes to collaborate? That's wild! It's like combining a pizza and a slice of bread into a glorious cake! &lt;/p&gt;

&lt;p&gt;It's easy to understand at a conceptual level. However, when we look at the actual implementation it can get a little tricky. In fact, I think most developers instinctively understand the &lt;strong&gt;adapter&lt;/strong&gt; pattern. They usually just lose their way during implementation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Dive Begins
&lt;/h2&gt;

&lt;p&gt;Let's take a deep dive into how this works with a working code example that we will build together. I will use Typescript for strict typing. It is probably most familiar to most people reading this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining the problem
&lt;/h3&gt;

&lt;p&gt;We want to implement payment code for our fancy new SAAS app. However, our target demographic is other companies. Those companies may want to use any number of preferred payment providers. &lt;/p&gt;

&lt;h3&gt;
  
  
  Determining potential solutions
&lt;/h3&gt;

&lt;p&gt;We have a few options. We can build out custom payment endpoints on an API for each payment method. The drawback here is having to maintain multiple sections of code that does the exact same thing.&lt;/p&gt;

&lt;p&gt;We can build out an &lt;strong&gt;adapter&lt;/strong&gt; pattern that contains the same payment code / interface across all payment types. We write the shared interface code once and handle our payment provider specific code in each payment providers code. This abstracts it so that we can ignore complexities.&lt;/p&gt;

&lt;p&gt;We can also just tell people to use one payment provider. However, they might not like that. So let's avoid it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing a sotution
&lt;/h2&gt;

&lt;p&gt;The code below lays the groundwork for our fancy new &lt;strong&gt;adapter&lt;/strong&gt; pattern. The code creates a new interface (a set of methods and attributes that code implementing it must have to be valid) that defines methods for our adapters. These methods will be the same no matter what payment provider we are using.&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PaymentsProvider&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;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paypal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;braintree&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adyen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;getPayments&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;getPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;updatePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;deletePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Define our payment structure&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currency&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Defines the provider type as a union of defined providers&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StripeProvider&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PayPalProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Provides and example payment object&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;paymentResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt; &lt;span class="o"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay. So we now have a way to define how we should interaction with payment providers. We also built out the payment structure. In addition to the payment structure we built out a sample payment object. We will use all of this later. For now, let's build an example adapter.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;StripeProvider&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;PaymentsProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;getPayments&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;paymentResponse&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;getPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;paymentResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;createPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;paymentResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;updatePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;paymentResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;deletePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is all boilerplate. However, in a real world situation you would write all of your payment provider specific code in these payment provider classes.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Payments&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;providers&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="nx"&gt;key&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="nx"&gt;Provider&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="nx"&gt;addProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;getProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;provider&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="nx"&gt;Provider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;getProviders&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;removeProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;provider&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;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the provider manager. It'svery similar to a builder method. It's how I prefer to handle these. It's simple and easy to understand while keeping it easy to maintain. Let's move onto seeing it put together!&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;StripeProvider&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PayPalProvider&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getProviders&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;getPayments&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paypal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;getPayments&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can view the full example source code below.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/brentvdalling/embed/PoaWBXo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you found this helpful please leave a like and bookmark. Please leave a comment! Let's discuss where we can use this! If you spotted a problem with the information provided please leave a comment and let me know. Let's have a healthy discussion! Thanks for reading!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>beginners</category>
      <category>codepen</category>
    </item>
    <item>
      <title>JS: Filter, Map, and forEach explained.</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Fri, 04 Nov 2022 17:07:06 +0000</pubDate>
      <link>https://forem.com/brentdalling/js-filter-map-and-foreach-explained-hmc</link>
      <guid>https://forem.com/brentdalling/js-filter-map-and-foreach-explained-hmc</guid>
      <description>&lt;p&gt;We've all been there as developers. We've got an array of data that we need to loop through. As a junior developer you might not know which built-in JS function to use. So you go to Stackoverflow. You see solutions to your problem using &lt;code&gt;.filter()&lt;/code&gt;, &lt;code&gt;.map()&lt;/code&gt;, and &lt;code&gt;.forEach()&lt;/code&gt;. But what are these? And, when should you really use them? Let's find out.&lt;/p&gt;

&lt;h4&gt;
  
  
  .filter
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.filter&lt;/code&gt; does excactly what it sounds like. It loops through the iterable object or array and returns a new value. For this reason you should never use this function for just the looping side-effect. As using it for this reason causes more memory to be assigned in your application. &lt;/p&gt;

&lt;p&gt;Let's review the proper usage of this built-in javascript function and compare it against the side-effect usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Proper Usage
const fruits = ['apple', 'orange', 'kiwi']

const fruitsMinusKiwi = fruits.filter(fruit =&amp;gt; {
    return fruit !== 'kiwi'
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Improper Usage (Side-effect)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first look they seem similar. They even seem to use the same amount of memory and time to complete. One simply filters the array and one simply logs the contents. The usage that logs the contents doesn't actually assign any values. So this is okay right? Well, no. Not really. This function does go through the extra step of attempting to return the values. &lt;/p&gt;

&lt;p&gt;This difference is honestly negligible in most apps. In fact, you probably don't even need to worry about it. However, if you are ever working on large scale applications that require highly available and performant resources for thousands of active end-users then this absolutely matters. &lt;/p&gt;

&lt;p&gt;See, as the dataset we are looping though increases. So does our completion time. For example, if this loop takes 2ms for 10 records to loop through using the proper usage and 3ms for the improper usage. Then you have 2ms and 3ms respectively. However, let's add 10,000 records to loop through. Now we have 2 seconds and 3 seconds respectively. The improper usage now takes a full second longer to complete its code.&lt;/p&gt;

&lt;h5&gt;
  
  
  // Resources &amp;amp; Links
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of/"&gt;https://leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of/&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  .map
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.map&lt;/code&gt; is very similar to the &lt;code&gt;.filter&lt;/code&gt; function. However, this built-in function does't try to return a new filtered array. Instead, this function returns a new array with all returned data. Technically you can still filter by just not returning anything for the current iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Proper Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Improper Usage (Side-effect)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;// Improper Usage (pushing to array rather than assign)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&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;The above incorrect examples show us either using &lt;code&gt;.map&lt;/code&gt; as a side-effect to simply log a fruit or as a loop to push to a different array fruit values in lowercase form. Both of these use more memory than is required. In small projects this is likely fine. However, just like the &lt;code&gt;.filter&lt;/code&gt; use-case, doing this incorrectly will result in larger computational time requirements in large data-set environments.&lt;/p&gt;

&lt;h4&gt;
  
  
  .forEach
&lt;/h4&gt;

&lt;p&gt;This built-in function doesn't actually return anything. Instead, it is a literal for loop that just iterates through an iterable and provides each value in a callback. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&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;Both are correct ways of iterating through an object without generating more data. Rather, you are taking already available data in the memory space and are reading or manipulating it. For example, let's lowercase our values. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Note, since these don't return anything (void functions) we need to have a variable outside of the loop scope to record our lowercase values. &lt;/li&gt;
&lt;li&gt;Therefore these should not be used in an instance where you need data out. Rather use a &lt;code&gt;.filter&lt;/code&gt; or &lt;code&gt;.map&lt;/code&gt; function.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="o"&gt;---&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&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;Not&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;---&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kiwi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fruitsLowerCased&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Okay. So we have an understanding of how these work and how to use them. Let's look at a few real world examples. Checkout the example below!&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/brentvdalling/embed/preview/OJZzGML?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;-- &lt;br&gt;
If you enjoyed this article please drop a comment and share what you learned! Did I miss something? If so, please let me know!&lt;/p&gt;

</description>
      <category>explainer</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Mobile App Architecture</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Fri, 07 Jan 2022 16:36:09 +0000</pubDate>
      <link>https://forem.com/brentdalling/mobile-apps-native-vs-hybrid-vs-pwa-vs-webview-2e5m</link>
      <guid>https://forem.com/brentdalling/mobile-apps-native-vs-hybrid-vs-pwa-vs-webview-2e5m</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;a href="https://unsplash.com/photos/EaB4Ml7C7fE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditShareLink"&gt;Image by @goshua13&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is an informative post on the different kinds of mobile apps you can build. We will discuss the technology behind them. And, we will look at some common pro's and con's. We do not endorse one solution over the other. And, we are not attempting to persuade you into using any of these solutions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A new project owner has approached your business. They have decent funding. But, they don't yet have a development team to build their project. After a couple of project meetings it is determined they want to build an app. &lt;/p&gt;

&lt;p&gt;The app should be easily update-able and be performant enough to enjoy. The app should also be completed in the next three months and be available on Android, iOS, and the web. This project is now being sent to the development team.&lt;/p&gt;

&lt;p&gt;One of the first steps in this process is determine what kind of app architecture we should build with. The good news is that there is a plethora of solutions that can fit this project. &lt;/p&gt;

&lt;p&gt;We can build native applications for each platform. Or, we could build a hybrid app using React Native. We could even build a web app with a service worker to enable a PWA experience. Or, we can build a simple shell app and provide a webview to the main app. &lt;/p&gt;

&lt;p&gt;All of these options are viable. Let's review each type of app so that we may determine which is most suitable for this use-case. Through this process we hope to learn you a thing or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Apps
&lt;/h2&gt;

&lt;p&gt;Native apps are apps written in the native language or ecosystem of an OS or community. An example would be writing an app in Java for Android. Or, writing an app in Swift for iOS. These apps normally have better performance and are sometimes easier to maintain. &lt;/p&gt;

&lt;p&gt;Why do they have better performance you ask? Well, it is simple really. You are not running any abstraction layer. You have powerful memory management and diagnostic tools if the app is written properly. And, you are not running a sub-app to render the main-app in which the users interact.&lt;/p&gt;

&lt;p&gt;Native apps are able to take advantage of native solutions and libraries more easily than hybrids. This is because native apps have been around longer than hybrids. This fact is becoming less true and the industry marches forward though. In the near future we may see just as many native/hybrid packages. (Packages are code libraries that help solve a problem)&lt;/p&gt;

&lt;p&gt;Okay. So they can manage their memory and their native packages mo' better. But, how are they easier to maintain? I'm glad you asked! Okay. So, native apps are easier to maintain for a couple of different reasons. Let's look at API changes and community support.&lt;/p&gt;

&lt;p&gt;Their packages and programming API's change less frequently than other solutions. This is thanks to the communities and companies behind the popular platforms. Let's take Android for example. You can still target Android 4! iOS can still target iOS 8! That means that your app can still be written to target these OS versions and their API's will still work! Pretty cool right? &lt;/p&gt;

&lt;p&gt;I admit. This argument can be kind-of weak. Especially since the hybrid app community is making numerous improvements. We will explore hybrid apps next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hybrid Apps
&lt;/h2&gt;

&lt;p&gt;Hybrid apps are apps that take advantage of native functionality while providing an abstraction layer to another interface. Common examples of this would be React Native, NativeScript, Flutter, and Ionic. These work by providing native API's to speak to the native app wrapper. Then, you code in your favorite framework to build your app. We will be exploring Javascript specific Hybrid Apps.&lt;/p&gt;

&lt;p&gt;There are some major benefits to this approach. Hybrid apps can be built for different platforms at the same time. Most React Native apps can be built for iOS, Android, and the web. This reduces the workload required to target these other platforms. This also means the teams working on projects tend to be less specialized which reduces project owner costs further.&lt;/p&gt;

&lt;p&gt;Hybrid apps also are easier for UI design and development. This is thanks to their common HTML structure (Not talking about Flutter here). Anything you can design in the browser can be built into to a hybrid mobile app. This also allows developers to break from the OS ecosystems design system more easily.&lt;/p&gt;

&lt;p&gt;Hybrid apps tend to rely on countless community packages (software packages that solve a problem) to interact with native API's.  There are numerous advantages and/or disadvantages here. Let's touch on a couple of benefits first.&lt;/p&gt;

&lt;p&gt;First, these community packages tend to provide a wrapper around the native API. These wrappers are usually not 1 to 1 with the API's they are wrapping. This means they tend to simplify API usage or add additional functionality to the API. This can be extremely useful for when you are interacting with some difficult native API's. This wrapper layer also allows the hybrid app to write one set of code and target two or more operating systems. &lt;/p&gt;

&lt;p&gt;Community packages can introduce major risk to a project as they tend to be updated more frequently. This is because they are normally not developed with the full weight of a major tech company. They tend to be community hobby projects. Or, a solution that was developed specifically for another company that was eventually open-sourced. Community packages also introduce security risk into your project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note: Security risks can be introduced through community packages. This is because so many developers have their hands in the cookie jar here. They can be intentional security holes. Or, they could be included by accident. But, when you use a popular community package, attackers can more easily exploit your project when a security hole is found and exploitable. (looking at you Log4J) This problem is present in any programming environment that the developer chooses to include community packages. This is not isolated to Hybrid Apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hybrid apps tend to be performant. But, they can also be a little slower than native apps. This is because the Hybrid app is being rendered by the native app integration. You are essentially running two apps in one. This is less noticeable as of recently. Our devices are becoming faster and more capable. &lt;/p&gt;

&lt;h2&gt;
  
  
  PWA
&lt;/h2&gt;

&lt;p&gt;This one will be veeery short. A PWA (Progressive Web App) is a website that registers a service worker for offline capabilities. These are not inherently bad. But, should serve as a saved website on a mobile device more than anything. Please do not depend on true PWA's for client work that needs more than a "bookmark" of sorts.&lt;/p&gt;

&lt;p&gt;PWA's are essentially a bookmark that the mobile OS saves to the home screen. You can access them like an app. Android treats them more like an app than iOS. iOS you have to click "share" then "save to home" to install the PWA. Android on the other hand will allow you to click a button that installs the service worker.&lt;/p&gt;

&lt;p&gt;PWA's can be very convenient and allow for truly rapid development. However, they are very lightweight and lack any access to native API's. They also can not be listed on app stores.&lt;/p&gt;

&lt;p&gt;Performance here is determined by the speed of the internet connection. All content must be delivered by a web page. This can be not ideal when internet connections might be weaker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webview
&lt;/h2&gt;

&lt;p&gt;Webviews are a native app strategy that aim to create a PWA experience within an app container. The advantage to this is using "some" of the native API's provided by the OS. However, through our research we have found that these apps tend to be rejected or de-listed from app stores as they can be difficult to scan for malicious code. And, they don't meet app store policies. &lt;/p&gt;

&lt;p&gt;Webviews work by having a real native app host an internal browser without showing the browser controls. (Basically how the OS treats a PWA) The webview can talk via webhooks to the website api. And, the native app can receive data from it as well. The part that typically violates the app store policies is that they can not look at the code. And, there is no content moderation available to the app stores. &lt;/p&gt;

&lt;p&gt;Performance here is determined by the speed of the internet connection. All content must be delivered by a web page. This can be not ideal when internet connections might be weaker.&lt;/p&gt;

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

&lt;p&gt;There are many app building strategies and architectures out there. What you use will likely depend on the needs of you project. Let's review.&lt;/p&gt;

&lt;p&gt;Our new client project meets a lot of criteria for the PWA. However, we know this is not the best option after reviewing what each app type is and how they work. What we can determine is that the best option for this project is a Hybrid app. We can target multiple operating systems simultaneously and provide a small development team. This will reduce the cost to the project owner while promoting a dependable app. We can push regular updates to the app stores more quickly than native apps as we can develop the fix for every platform at the same time.&lt;/p&gt;

&lt;p&gt;We hope that you have a better understanding of the general app architectures and how they work. This article is meant to be a broad overview.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Native&lt;/th&gt;
&lt;th&gt;Hybrid&lt;/th&gt;
&lt;th&gt;PWA&lt;/th&gt;
&lt;th&gt;Webview&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native Support&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follows Store Policies&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowers Project Cost&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reduces Technical Debt&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowers Project Risk&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Please listen to the project sponsor or owner regarding the needs of the project and business. These will typically steer your decision making towards something ideal for them. Every project will have different requirements. These requirements will inform your decision making. You may not even use any of the general architectures mentioned in this article. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What are your thoughts? Did we get anything wrong? Is there another app architecture you prefer? Do you have a solution to the Webview policy issues? If so, let us know in the comments!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Is TailwindCSS Worth It?</title>
      <dc:creator>Brent Dalling</dc:creator>
      <pubDate>Thu, 06 May 2021 16:58:10 +0000</pubDate>
      <link>https://forem.com/sparkfish/is-tailwindcss-worth-it-3ppc</link>
      <guid>https://forem.com/sparkfish/is-tailwindcss-worth-it-3ppc</guid>
      <description>&lt;p&gt;Is TailwindCSS worth it? Tailwind is a utility CSS framework that depends on the developers using it to also know a little CSS. It is lightly opinionated but simple. Do these points together make it harder to use for unfamiliar developers?&lt;/p&gt;

&lt;p&gt;Since Tailwind is a utility CSS framework it means that every provided class is a utility. These utilities range from text formatting to flex-box management and more. ex:&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;flex flex-row justify-center&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 This is fine. But did you notice these classes are familiar? I mean really look at them. They look like plain old CSS without the extra hassle! For example:&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;display: flex; flex-direction: row; justify-content: center;&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 becomes&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;flex flex-row justify-center&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;You may be asking yourself how this could possibly be useful. You might even be telling yourself that you could save the learning curve and just write plain CSS inline or in a stylesheet. That might be true. But you would be missing the point of Tailwind and the problems it solves. These near plain old CSS like classes can actually be used to solve many problems that regular development faces such as rapid prototyping and effects. &lt;/p&gt;

&lt;p&gt;Let's build a simple card example for those Bootstrap fans out there to demonstrate how powerful Tailwind can be. (Yes. I know you exist and overuse the card component regularly.) We will show the source for the card with inline CSS and Tailwind. This should enable you to see the difference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="w-1/3 mx-auto my-2 shadow-sm rounded-lg"&amp;gt;
    &amp;lt;div class="bg-gray-100 text-gray-600 px-3 py-2 text-lg font-semibold rounded-t-lg"&amp;gt;Header&amp;lt;/div&amp;gt;
    &amp;lt;div class="bg-white text-gray-600 p-3 rounded-b-lg"&amp;gt;
      This is a card example in Tailwind CSS.
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style="width: 33.33%; margin: 1rem auto; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); border-radius: 7.5px;"&amp;gt;
    &amp;lt;div style="background-color: #f4f5f7; color: #4b5563; padding: .6rem .75rem; font-weight: 520; font-size: 1.1rem; border-top-left-radius: 7.5px; border-top-right-radius: 7.5px;"&amp;gt;Header&amp;lt;/div&amp;gt;
    &amp;lt;div style="background-color: white; color: #4b5563; padding: .75rem; border-bottom-left-radius: 7.5px; border-bottom-right-radius: 7.5px;"&amp;gt;This is a card example in inline CSS.&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This renders into the image below: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzzskf8gny2xasw8la8j.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzzskf8gny2xasw8la8j.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay. So Tailwind does save a little time and overhead if you are writing everything inline. But this is not maintainable! How are you supposed to update your site if you have to go into every tag and update it? Well Tailwind is meant for you to rapidly prototype like we did above and then convert to actual semantic CSS classes. If you have ever used other CSS Frameworks or written your own classes you will recognize them as&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;.card {}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Tailwind provides a utility if installed using NPM that allows you to compile all those styles you prototyped with into semantic CSS. Please follow this &lt;a href="https://tailwindcss.com/docs/installation" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to understand how we get here. Once you have read this guide then continue reading! Or continue if you are already familiar with the TailwindCSS installation and setup.&lt;/p&gt;

&lt;p&gt;Once we have our prototyped components we can easily convert them into simple to use classes. All you have to do is name your semantic class and drop in everything inside your &lt;strong&gt;&lt;em&gt;"class"&lt;/em&gt;&lt;/strong&gt; tag. Ex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.card {
    @apply "mx-auto my-2 shadow-sm rounded-lg";
}

.card-header {
    @apply "bg-gray-100 text-gray-600 px-3 py-2 text-lg font-semibold rounded-t-lg";
}

.card-body {
    @apply "bg-white text-gray-600 p-3 rounded-b-lg";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our new semantic CSS classes we can now convert our component! Just replace those long utility class-lists with your semantic class. Ex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="w-1/3 card"&amp;gt;
    &amp;lt;div class="card-header"&amp;gt;Header&amp;lt;/div&amp;gt;
    &amp;lt;div class="card-body"&amp;gt;
      This is a card example in Tailwind CSS.
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow! That is so much cleaner! Once you get to know how Tailwind is supposed to be used and have practiced it you can quickly see why Tailwind &lt;strong&gt;&lt;em&gt;is&lt;/em&gt;&lt;/strong&gt; worth it! It can save you time on larger design projects while empowering you to convert back to semantic CSS classes painlessly! Tailwind is also powerful for those not very familiar with plain old CSS as it cuts down on the overhead statements such as "flex-direction: row" and makes it as simple as "flex-row"!&lt;/p&gt;

&lt;p&gt;Tailwinds learning curve is in my opinion simpler for those who have little to no CSS experience than actually learning CSS. It empowers teams of any size to prototype faster while compiling into maintainable source code. It even helps CSS professionals!If you enjoyed this article and want to learn more please visit Tailwinds website &lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>semantic</category>
      <category>css</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
