<?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: Ridhwana Khan</title>
    <description>The latest articles on DEV Community by Ridhwana Khan (@ridhwana).</description>
    <link>https://dev.to/ridhwana</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%2F247560%2F803f25c6-05a3-4cff-932d-20dbe4915cb3.jpg</url>
      <title>DEV Community: Ridhwana Khan</title>
      <link>https://dev.to/ridhwana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ridhwana"/>
    <language>en</language>
    <item>
      <title>Reflecting on my journey in tech</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Mon, 13 Mar 2023 08:18:41 +0000</pubDate>
      <link>https://dev.to/devteam/reflecting-on-my-journey-in-tech-2lk9</link>
      <guid>https://dev.to/devteam/reflecting-on-my-journey-in-tech-2lk9</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://www.pexels.com/photo/green-tree-268533/"&gt;Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As another year approaches and we celebrate individuals who are underrepresented and otherwise marginalized in software development, I took the time to reflect on my journey. &lt;/p&gt;

&lt;p&gt;Back in March 2019, almost 4 years ago, I talked about my experiences as an underrepresented person in the tech industry and I shared the choices that I had made.&lt;/p&gt;

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

&lt;p&gt;My experiences have evolved since I last discussed it as that young woman on stage. I feel safer, more confident and more hopeful about the future after working with companies like Forem that value equality in the workplace and continuously try to move the &lt;a href="https://dev.to/ben/lets-keep-moving-the-goal-posts-3jjl"&gt;goal posts&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, I still continue to practice those choices that I made many years ago:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To educate folks in the industry about the issues that we deal with as minorities. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To urge the people that I meet to be active participants in the struggle. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To mentor the next generation of leaders so that they are better equipped to deal with what’s thrown their way than I was, so that they may overcome these issues more easily and eventually eliminate them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To speak up about these issues and create an  awareness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To surround myself with folks whom I can identify with and whom I can form a support system with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To no longer doubt myself. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I still practice these choices everyday and I want to be reminded about them often so that I continue playing my part in helping to promote equality, diversity and inclusion in the tech industry.&lt;/p&gt;

</description>
      <category>wecoded</category>
      <category>womenintech</category>
    </item>
    <item>
      <title>Caching at DEV</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Fri, 10 Feb 2023 13:15:06 +0000</pubDate>
      <link>https://dev.to/devteam/caching-at-dev-11el</link>
      <guid>https://dev.to/devteam/caching-at-dev-11el</guid>
      <description>&lt;p&gt;We’ve always put a lot of effort into performance at DEV. We want our users to be able to see their content almost instantaneously when interacting with our content. In order to do so we’ve placed a big emphasis on caching. We’ve had to ask ourselves questions like what are the right things to cache? Which layer in the stack would be best to cache it? And how will this affect the overall performance? &lt;/p&gt;

&lt;p&gt;As someone reading this post, you’re most likely a user of DEV 🙌🏼 which means that you know that DEV is a read-heavy site. Tens of thousands of users all around the world are reading content on our site at any point in the day. This content - for example, an article, once created will rarely change and so we can refer to it as “mostly” static content. There are also more interactive bits with DEV like being able to react to and comment on posts which provides us with interesting caching opportunities.&lt;/p&gt;

&lt;p&gt;There are many types of caching that we apply in the application, however in this post we'll be discussing Response Caching specifically.  At the core of our response caching strategy, we identify the static content and try to cache it so that users are not making a trip to our servers for each request. &lt;/p&gt;

&lt;h2&gt;
  
  
  Types of response caching on DEV
&lt;/h2&gt;

&lt;p&gt;There are many types of response caching that occur in different layers of the application stack. One of the important decisions that you’ll make when developing features is to decide on which part of the stack you should implement caching. &lt;/p&gt;

&lt;p&gt;💡 &lt;em&gt;Do we implement caching to avoid hitting the origin server completely in the form of Edge caching?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 &lt;em&gt;Do we implement caching at the view layer to reduce the number of database queries and complex rendering of the UI in the form of Fragment caching?&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;💡 &lt;em&gt;Or do we implement Browser caching to constrict our request to never leave our browser?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each of these strategies has different use cases and sometimes we may end up using a combination of multiple caching techniques on one feature to achieve the most optimised result. &lt;/p&gt;

&lt;p&gt;Have you ever wondered why the article page on DEV loads up so quickly - even when the page is really long and there are tons of images it’s still pretty snappy! That’s mostly due to edge caching, and when the edge cache is being refreshed, you can thank Fragment caching for stepping in. The assets load pretty quickly on that page as well, we can thank the browser cache for caching our JavaScript and CSS for those pages. &lt;/p&gt;

&lt;p&gt;Let’s go into more detail about each of these types of caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡️ Edge Caching
&lt;/h3&gt;

&lt;p&gt;Edge Caching lives between the browser and the origin server, thus reducing the need to make a trip to the origin server for every request. Its where we add an intermediary storage (ideally closer to the user) between the user and the server to store the data for a period of time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we edge cache at DEV?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two parts of edge caching at DEV that make it beneficial for the application: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Edge caching moves memory storage closer to the end users by adding a machine ahead of the origin server. This means that a user from South Africa will get content served from a point of presence in Cape Town which contains the edge cache instead of going all the way to the origin server in the United States - the trip ends up being much faster. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The edge cache contains a cached version of the page that the user is requesting without having to do any re-computation thus making the response time really really fast. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of the benefits of the edge cache include reducing server load and stress on the origin server, improving content delivery and response times of requests thus reducing waiting time on web pages, and lightening the network load by reducing the amount of duplicate data. &lt;/p&gt;

&lt;p&gt;At DEV we currently use &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt; or &lt;a href="https://www.fastly.com/" rel="noopener noreferrer"&gt;Fastly&lt;/a&gt; for our edge cache. In the future, we hope to allow for our configuration to be scalable enough to run through any caching intermediary. &lt;/p&gt;

&lt;p&gt;Currently Fastly caches the content stored on our origin server at points of presence (POPs) around the world which then improves the user experience of our site. &lt;/p&gt;

&lt;p&gt;Within our Fastly configuration we have &lt;a href="https://docs.fastly.com/en/guides/shielding" rel="noopener noreferrer"&gt;shielding&lt;/a&gt; enabled. When one of Fastlys POPs is used as an "origin shield" it will reduce the load on the origin server. Thus, the requests to the origin will come from a single POP, thereby increasing the chances of an end user request resulting in a cache HIT.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does edge caching actually work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user navigates to our site &lt;a href="https://dev.to/"&gt;https://dev.to/&lt;/a&gt;, they first hit our edge cache. Within this layer, the edge server will either have a warm cache or a cold cache.&lt;/p&gt;

&lt;p&gt;Usually, the first visit to a site after a cache is set up or after it expires will reach a “cold” cache.  A cold cache is an empty one that does not have any data stored. When a cache is “cold”, then the request will make its way to the origin server to retrieve the data, and it will be labeled a cache “MISS”. However, when it does this it also retains the data that it got from the origin server within the cache. This is referred to as the process of ‘warming’ the cache. A warm cache will contain data that is already stored and prepared to serve users. If the cache is warm, the data is returned from the cache to the browser and it will be labeled as a “HIT”. Every subsequent user will hit a warm cache until we expire or purge the cache and the same process repeats itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiring a cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When caching objects it’s important to think about how long you want the cache to be around until it gets stale. One approach is to set a reasonably longer cache lifetime and then purge the cache on certain conditions &lt;/p&gt;

&lt;p&gt;When we want our content to be edge cached we &lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/controllers/stories_controller.rb#L21" rel="noopener noreferrer"&gt;set the appropriate cache control headers&lt;/a&gt;. Here’s a snippet of the code that we use in the DEV codebase:&lt;/p&gt;

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

 before_action :set_cache_control_headers, only: %i[index show]


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/controllers/concerns/caching_headers.rb#L20-L38" rel="noopener noreferrer"&gt;&lt;code&gt;set_cache_control_headers&lt;/code&gt;&lt;/a&gt; is defined with the following configuration: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_cache_control_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;max_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;surrogate_control: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;stale_while_revalidate: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="ss"&gt;stale_if_error: &lt;/span&gt;&lt;span class="mi"&gt;26_400&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;# Only public forems should be edge-cached based on current functionality.&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UserExperience&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public&lt;/span&gt;

   &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:skip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# no cookies&lt;/span&gt;

   &lt;span class="no"&gt;RequestStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:edge_caching_in_place&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# To be observed downstream.&lt;/span&gt;

   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Cache-Control"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"public, no-cache"&lt;/span&gt; &lt;span class="c1"&gt;# Used only by Fastly.&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"X-Accel-Expires"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="c1"&gt;# Used only by Nginx.&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Surrogate-Control"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;surrogate_control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presence&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;build_surrogate_control&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="n"&gt;max_age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;stale_while_revalidate: &lt;/span&gt;&lt;span class="n"&gt;stale_while_revalidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;stale_if_error: &lt;/span&gt;&lt;span class="n"&gt;stale_if_error&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;max-age&lt;/code&gt; header will help the edge cache server to calculate a Time To Live (TTL) for the cache. TTL is the maximum amount of time that the content will be used to respond to requests. Thereafter, the cache will need to be revalidated by consulting the origin server. TTL is defined in seconds. For DEV we set the default &lt;code&gt;max-age&lt;/code&gt; to be 1 day, however, in some cases, we may override this value. We override this value &lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/controllers/stories_controller.rb#L133-L135" rel="noopener noreferrer"&gt;for caching of the feed&lt;/a&gt; where we set the &lt;code&gt;max-age&lt;/code&gt; to be two hours. I encourage you to grep for &lt;code&gt;set_cache_control_headers&lt;/code&gt; in the codebase to explore the length of the caches for the various controller actions. &lt;/p&gt;

&lt;p&gt;In case you’re curious about those other values in the snippet of code above: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;stale-while-revalidate&lt;/code&gt; tells caches that they may continue to serve a response after it becomes stale for up to the specified number of seconds, provided that they work asynchronously in the background to fetch a new one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stale-if-error&lt;/code&gt; tells the caches that they may continue to serve a response after it becomes stale for up to the specified number of seconds in the case where the check for a fresh one fails (in most cases where there is an issue at the origin server).&lt;/p&gt;

&lt;p&gt;Some best practices worth outlining are that it is recommended to specify a short &lt;code&gt;stale-while-revalidate&lt;/code&gt; and a long&lt;code&gt;stale-if-error&lt;/code&gt; value. The &lt;a href="https://developer.fastly.com/learning/concepts/stale" rel="noopener noreferrer"&gt;Fastly docs rationale for recommending this&lt;/a&gt; is that if your origin is working, you don't want to subject users to content that is significantly out of date. But if your origin is down, you're probably much more willing to serve something old if the alternative is an error page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purging a cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Expiring a cache allows a cache to be populated with fresh data periodically, however, there are times when you’d want to refresh the cache based on actions. This is where purging becomes useful. Purging describes the act of explicitly removing content from the edge cache, rather than allowing it to expire or to be evicted. &lt;/p&gt;

&lt;p&gt;You’ve read above that we expire the cache on an article page after one day, but what if after publishing the article, the author realizes that they made some typos and they update the article? In this case, we wouldn’t want readers to continue viewing the outdated version with the typos. We’d want to “purge” that cache so that we can get the latest version from the origin server. Hence, when creating a cache you want to evaluate the conditions for which you’d need to purge the cache. In the case of the article page, we purge the cache on some of these actions below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/controllers/discussion_locks_controller.rb#L47-L49" rel="noopener noreferrer"&gt;Changes in discussion locks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/models/article.rb#L935-L942" rel="noopener noreferrer"&gt;create, update or delete an article&lt;/a&gt;, &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/workers/comments/bust_cache_worker.rb#L8" rel="noopener noreferrer"&gt;create, read, update or delete comments on the article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;update a users name and profile image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above are some of the main cases where we purge the article, however, it is not the exhaustive list. &lt;/p&gt;

&lt;p&gt;You can read more about Purging on the &lt;a href="https://developer.fastly.com/learning/concepts/purging/#soft-vs-hard-purging" rel="noopener noreferrer"&gt;fastly developer documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observing edge caching on DEV&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can observe edge caching on an article page on DEV. &lt;/p&gt;

&lt;p&gt;When you load up a page like &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-from-the-past-week-3id8"&gt;https://dev.to/devteam/top-7-featured-dev-posts-from-the-past-week-3id8&lt;/a&gt;, you’ll notice that the content of the article page loads really quickly but then the reactions take some time to come in. This is due to the fact that the first time we render the page, we hit an edge cache, and the article gets rendered from that cache. We then make a follow-up asynchronous request to get the reactions that are not needed immediately. From a user experience point of view, you’re most likely keeping your eye on the content to read the article before reacting to it. It's also useful to note that the comments are rendered along with the article on the first load, and this is mostly for SEO purposes. &lt;/p&gt;

&lt;p&gt;In order to see whether a request is cached, you can click on the request in the network tab and look at the request headers. The request headers have an &lt;a href="https://developer.fastly.com/reference/http/http-headers/X-Cache/" rel="noopener noreferrer"&gt;&lt;code&gt;x-cache&lt;/code&gt; attribute which is written by Fastly&lt;/a&gt; which indicates whether the request was a HIT or a MISS. It also contains a header &lt;code&gt;X-cache-hits&lt;/code&gt; which indicates the number of cache hits in each node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F827kybvodhpnoonimu2q.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%2F827kybvodhpnoonimu2q.png" alt="A network request with Fastly headers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are useful headers to look out for to determine if the requests are being cached. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡️ Fragment Caching
&lt;/h3&gt;

&lt;p&gt;Fragment Caching is used to cache parts of views, thus reducing the need to re-compute complex views&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we fragment cache at DEV?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a typical Rails application, when a user visits a page on the site then a request to load the page would get sent to the Rails application. The application will then call the relevant controller which in turn will request the model for the data. The model fetches the data from the database and returns it to the controller. The controller, armed with the data, will render the view which is the user interface that you as a user will see on the web page. &lt;/p&gt;

&lt;p&gt;However, that rendering can be slow for numerous reasons. Some of these include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There can be expensive database queries in the view. &lt;/li&gt;
&lt;li&gt;It may be a complex view with nested loops and we have tons of complex views at DEV.&lt;/li&gt;
&lt;li&gt;There may also be many partials with some being nested which can increase rendering time. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, to avoid the slowness that comes with the above problems, we sometimes cache the view to allow the request to complete more quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does fragment caching work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fragment caching removes the call to our Postgres database and reduces the time taken to compute a view in favor of storing the “fragment” in a memory cache (like &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;) as key-value objects. The key is provided within the Rails application and the fragment is stored as its value. &lt;/p&gt;

&lt;p&gt;During the view rendering, if a cache key is come upon, it checks the Redis store for that cache key, if it finds the cache key, it reads the value of the cache key which is the Fragment, and renders it within the block. If it does not find the cache key, it will then compute the view, and write that key to the Redis store for next time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiring a cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A unique key is provided for every fragment that will be cached in our Rails view. Below is an example of &lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/_full_comment_area.html.erb#L1-L2" rel="noopener noreferrer"&gt;one of our more complex cache keys that rely on numerous identifies &lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% cache("whole-comment-area-#{@article.id}-#{@article.last_comment_at}-#{@article.show_comments}-#{@discussion_lock&amp;amp;.updated_at}-#{@comments_order}-#{user_signed_in?}", &lt;/span&gt;&lt;span class="ss"&gt;expires_in: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
...


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

&lt;/div&gt;

&lt;p&gt;This view touches a few different resources, and hence you’ll notice the different dynamic aspects that make up the cache key. The cache key allows the cache to be purged each time it changes. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;#{@article.id}&lt;/code&gt; requests that we maintain a cache of the comments section for every article page. &lt;code&gt;#{@article.last_comment_at}&lt;/code&gt; will change when we add a new comment, and hence we’d want to refresh the cache. If a user chooses to not show the comments &lt;code&gt;@article.show_comments&lt;/code&gt; or to lock a discussion thread &lt;code&gt;discussion_lock&amp;amp;.updated_at&lt;/code&gt;, we want it to refresh the fragment cache as well. If a parameter is passed through that changes the sorting order of the comments &lt;code&gt;#{@comments_order}&lt;/code&gt;.Finally we show a different view fragment for logged in vs logged out view.&lt;/p&gt;

&lt;p&gt;When any of the above cache keys change then we’ll be writing to the Redis store.&lt;/p&gt;

&lt;p&gt;Another way that we get fresh data is by expiring the cache. Just like with edge caching, we can set an expiry time after which the cache will be refreshed. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observing fragment caching on DEV&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use fragment caching in numerous places on the DEV application, you can grep for &lt;code&gt;&amp;lt;% cache&lt;/code&gt; in our codebase to view these instances. Some include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/_full_comment_area.html.erb#L1-L2" rel="noopener noreferrer"&gt;Our comment area on the articles page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/_sidebar.html.erb#L3-L7" rel="noopener noreferrer"&gt;The left sidebar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/_sidebar.html.erb#L8-L23" rel="noopener noreferrer"&gt;Display Ads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/_sticky_nav.html.erb#L7-L55" rel="noopener noreferrer"&gt;The right hand navbar on an article page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/articles/index.html.erb#L28-L106" rel="noopener noreferrer"&gt;The home feed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just &lt;em&gt;some&lt;/em&gt; of the instances where we use Fragment caching, and each of these views are cached for one of the reasons outlined above.  &lt;/p&gt;

&lt;p&gt;In order to observe Fragment caching you can run &lt;code&gt;rails dev:cache&lt;/code&gt;. You can start off by clearing the cache with &lt;code&gt;rake tmp:cache:clear&lt;/code&gt; to ensure that the first partial is rendered by the server. Thereafter, spin up the DEV server locally and navigate to the article page.&lt;/p&gt;

&lt;p&gt;When you navigate to this page, you should be able to see the &lt;code&gt;whole-comment-area...&lt;/code&gt; partial being logged. &lt;/p&gt;

&lt;p&gt;On the first load when the cache is clear you will notice that we write to the cache &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="no"&gt;Cache&lt;/span&gt; &lt;span class="ss"&gt;write: &lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_full_comment_area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;83798&lt;/span&gt;&lt;span class="n"&gt;ee6f16a072196604860c4f72c64&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;whole&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt; &lt;span class="no"&gt;UTC&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:namespace&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress_threshold&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:expires_in&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:race_condition_ttl&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;       &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;781241634623167295&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;span_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="no"&gt;Cache&lt;/span&gt; &lt;span class="ss"&gt;write: &lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;136&lt;/span&gt;&lt;span class="n"&gt;d4e5867aa13a4886bc993aba6558e&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;specific&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;scripts&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt; &lt;span class="no"&gt;UTC&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:namespace&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress_threshold&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:expires_in&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:race_condition_ttl&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;However, on subsequent loads we’ll simply continue reading from the store.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;       &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2192981961066220961&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;span_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="no"&gt;Cache&lt;/span&gt; &lt;span class="ss"&gt;read: &lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_full_comment_area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;83798&lt;/span&gt;&lt;span class="n"&gt;ee6f16a072196604860c4f72c64&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;whole&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt; &lt;span class="no"&gt;UTC&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:namespace&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:compress_threshold&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:expires_in&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:race_condition_ttl&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;       &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rails&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2192981961066220961&lt;/span&gt; &lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;span_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="no"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;fragment&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_full_comment_area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;83798&lt;/span&gt;&lt;span class="n"&gt;ee6f16a072196604860c4f72c64&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;whole&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt; &lt;span class="no"&gt;UTC&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We realize that sometimes we may overuse Fragment caching at times in our application and there is probably some room for cleanup and improvement. One aspect to keep an eye on is the complexity of the cache keys. If the cache keys are more complex than the cached content then you may end up with a circumstance where it takes longer to check if there is a cache stored for that key in memory store than it does to render the view, then perhaps it's time to re-evaluate. Whilst Redis handles this very well and scales magnificently, sometimes the better path can be optimizing the database queries. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪆 Russian Doll Caching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you look through the application, we you will see that we sometimes nest the cached fragments inside other cached fragments - this is referred to as Russian Doll Caching. It ensures that our cached fragments are broken up into smaller pieces which allows  the outer cache to be rendered faster when only one of the nested fragments change.&lt;/p&gt;

&lt;p&gt;An example of Russian Doll Caching can be seen in the manner &lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/app/views/layouts/_main_nav.html.erb#L23-L24" rel="noopener noreferrer"&gt;that we render our navigation links&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= render partial: "layouts/sidebar_nav_link", collection: NavigationLink.where(id: navigation_links[:other_nav_ids]).ordered, as: :link, cached: true %&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;NavigationLink.where(id: navigation_links[:other_nav_ids]).ordered&lt;/code&gt; renders a navigation link collection. Hence,  using the collection attribute, we’re theoretically wrapping each navigation link  &lt;code&gt;layouts/sidebar_nav_link&lt;/code&gt; partial in a cache block. Each object in the collection contains the details of a navigation link, and so if any of that data is updated, the cache of that particular element will be invalidated whilst the outer cache and the other nested caches will remain unchanged. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡️ Browser Caching
&lt;/h3&gt;

&lt;p&gt;The Browser cache allows resources to be cached in one's browser, thus reducing the page load time and eliminating the need to go to the server. It stores resources in the web browser. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we browser cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At DEV we cache our static assets like images, CSS, and JavaScript. Previously, we had early adopted service workers as a form of browser caching but we later removed it when we ran into many caching bugs. We mainly browser cache to speed up the page loading process as well as minimize the load on the server. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the browser cache work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user makes a request for the first time on a site, the browser will request those resources from the server and store some of the resources in the browser cache. On subsequent requests, these resources will then be returned from the browser instead of having to travel over the internet to the user. &lt;/p&gt;

&lt;p&gt;In order to browser cache we set some headers in our &lt;a href="https://github.com/forem/forem/blob/b77c1ea2e63de9c36b3a53d29c7e9397afb0869f/config/environments/production.rb#L41-L43" rel="noopener noreferrer"&gt;&lt;code&gt;production.rb&lt;/code&gt;&lt;/a&gt;: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

 &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_file_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="s2"&gt;"Cache-Control"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"public, s-maxage=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, max-age=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here, we are first setting the Cache-Control header to use public (intermediate) caching, for 3000 days with &lt;code&gt;max-age&lt;/code&gt;. &lt;code&gt;s-maxage&lt;/code&gt; stands for Surrogate cache, which is used to cache internally by Fastly. When the browser sees the above cache-control header it will cache the asset for a year, thus the network calls will no longer hit the server. &lt;/p&gt;

&lt;p&gt;When the browser parses the index.html file it looks for the different referenced script files. You’ll notice that these files are fingerprinted. Hence the request for those files will look like &lt;code&gt;https://dev.to/assets/base-bb53898178e7a6557807ce845d06cd2d60fd1e7ab108f2bad351d5bb92ec53b9.js&lt;/code&gt;.  This versioning technique binds the name of a file to its content, usually by adding the file hash to the name.&lt;/p&gt;

&lt;p&gt;If a file has been updated on the server, the fingerprint changes as well which then results in the browser not having a reference to that filename in its cache. Hence, it refreshes the cache for that resource. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observing browser caching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From the screenshot below you can see that our js file returns a 200 (from memory cache) which shows that the response was indeed served from the cache. If you look at the Request Url you will notice that the file name is fingerprinted to let the browser know whether the resource has changed on the server or not. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wl2di3z454h4surhsvo.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%2F3wl2di3z454h4surhsvo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;To conclude, I’d like to discuss some of the questions I ponder on when trying to determine whether or not to implement caching on a feature. &lt;/p&gt;

&lt;p&gt;One of them is “How often do we see the data for that feature changing?” If the answer to that is very seldom and “relatively static” then caching is most likely the way to go. &lt;/p&gt;

&lt;p&gt;Another question that I ask is at what layer does it make sense to implement the caching? Here I think about what needs to be cached and how often will it need to be refreshed.&lt;/p&gt;

&lt;p&gt;If I think that caching is the way to go then I explore whether it would be beneficial to implement only Fragment caching to cache any complex views on that page. Hence, allowing the requests to still hit the server but reduce the load on the database by serving from the application cache.&lt;/p&gt;

&lt;p&gt;Or do I need something more, perhaps we anticipate a large load on the page, with successive hits from all around the world? In this case, edge caching will be more efficient in serving the page. Maybe it makes sense to do both, like we do in many parts of the DEV application.&lt;/p&gt;

&lt;p&gt;There’s no right or wrong answer here, but as with all performance problems, we encourage our team members and contributors to analyze the problem carefully and run some tests in order to make the most informed decision. &lt;/p&gt;

&lt;p&gt;And that’s all folks - I hope that you found this post useful. Please drop any feedback and comments below 👇🏽.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fen4ls4vpepbcofv2dd3e.gif" 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%2Fen4ls4vpepbcofv2dd3e.gif" alt="Thats all folks"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>tutorial</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Documenting Forem's v1 API</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Thu, 19 Jan 2023 15:53:29 +0000</pubDate>
      <link>https://dev.to/devteam/documenting-the-forem-v1-api-15ck</link>
      <guid>https://dev.to/devteam/documenting-the-forem-v1-api-15ck</guid>
      <description>&lt;p&gt;&lt;strong&gt;Forem has set a &lt;a href="https://github.com/forem/forem/milestone/10"&gt;milestone&lt;/a&gt; to update our (v1) API documentation and we need YOUR help!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are several endpoints that we would like to document in order to complete our v0 -&amp;gt; v1 upgrade. v0 will eventually be deprecated and removed (there aren't any breaking changes so existing endpoints will continue to work the same as before). &lt;strong&gt;If you’re looking to contribute to open source, these are awesome first issues to work on and this post will help guide you through them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post, I’ll outline the details about our v1 API, we’ll discuss its documentation and then I’ll walk you through an example of an API endpoint that I had recently documented. &lt;/p&gt;

&lt;h2&gt;
  
  
  About the v1 API
&lt;/h2&gt;

&lt;p&gt;The API is a REST (REpresentational State Transfer) API, which means that it follows a set of guiding principles that you can read more about &lt;a href="https://restfulapi.net/"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There are currently many resources that can be accessed via the API, however, it does not contain &lt;strong&gt;all&lt;/strong&gt; of the resources that we have available on DEV. We are continuously adding more endpoints to the API. &lt;/p&gt;

&lt;p&gt;It is important to note that all operations are scoped to a user at the moment, and one cannot interact with the API as an organization. &lt;/p&gt;

&lt;h3&gt;
  
  
  Headers
&lt;/h3&gt;

&lt;p&gt;The API consists of both authenticated and non-authenticated endpoints. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Most&lt;/em&gt; read endpoints do not require authentication and can be accessed without API keys. However, we require authentication for most endpoints that can create, update or delete resources, and those that contain more private information.&lt;/p&gt;

&lt;p&gt;CORS (Cross Origin Resource Sharing) is disabled on authenticated endpoints, however endpoints that do not require authentication have an open CORS Policy. With an open CORS policy you are able to access some endpoints from within a browser script without needing to connect via a server or backend. &lt;/p&gt;

&lt;p&gt;Authentication is granted via a valid API Key. The API key can be generated by logging into your account at dev.to and clicking on Generate API Key on the &lt;a href="https://dev.to/settings/extensions"&gt;Settings (Extensions) page&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Once you’ve generated your API key, you are ready to start interacting with the API. The API Key will be set as a header, namely &lt;code&gt;api-key&lt;/code&gt;, on a request. &lt;/p&gt;

&lt;p&gt;We require another header for accessing the v1 API - the &lt;code&gt;Accept&lt;/code&gt; header. The Accept header needs to be set to &lt;code&gt;application/vnd.forem.api-v1+json&lt;/code&gt;, where v1 is the version of the API. If you do not pass along an Accept header you will automatically be routed to v0 of the API. API (v0) will be deprecated soon and we encourage you to rather use v1. &lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing the API
&lt;/h3&gt;

&lt;p&gt;As mentioned above, there are some API endpoints that are authenticated and others that do not require authentication. &lt;/p&gt;

&lt;p&gt;When interacting with an endpoint that does not require authentication, you can pass through a single header (the &lt;code&gt;Accept&lt;/code&gt; header) that will set the version of the API that you are interacting with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X GET https://dev.to/api/articles\?page\=1 --header "accept: application/vnd.forem.api-v1+json"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;An endpoint that requires authentication would need both the &lt;code&gt;Accept&lt;/code&gt; and the &lt;code&gt;api-key&lt;/code&gt; header to be set when making the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X PUT http: //localhost :3000/api/users/1/unpublish
--header "api-key: &amp;lt;your-api-key&amp;gt;"
--header "accept: application/vnd.forem.api-v1+json" -V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to have the correct roles and permissions set on your user to be able to query certain data from the API. For example, only admins can read, create, update and delete Display Ad resources. &lt;/p&gt;

&lt;h2&gt;
  
  
  About our documentation
&lt;/h2&gt;

&lt;p&gt;Our v1 API endpoints are documented according to the OpenAPI Specification. &lt;/p&gt;

&lt;h3&gt;
  
  
  The OpenAPI Specification
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://swagger.io/resources/open-api/"&gt;OpenAPI Specification&lt;/a&gt; (previously known as a Swagger Specification) is a standard for defining RESTful interfaces. As per the definition on &lt;a href="https://swagger.io/resources/open-api/"&gt;their website&lt;/a&gt;, it is a document (or set of documents) that defines or describes an API.&lt;/p&gt;

&lt;p&gt;An OpenAPI definition uses and conforms to the OpenAPI Specification. The OpenAPI definition can be created within your codebase.&lt;/p&gt;

&lt;p&gt;You can view the Open API Specification &lt;a href="https://swagger.io/specification/"&gt;here&lt;/a&gt;. It describes API Versions, Formats, Document Structure, Data Types, Schemas and much more. &lt;/p&gt;

&lt;p&gt;When an API adheres to the Open API specification, it allows opportunities to use document generation tools to display the API, code generation tools to generate servers and clients in various programming languages, access to testing tools etc. Some of these tools include Swagger UI, Redoc, DapperDox and RapidDoc. &lt;/p&gt;

&lt;p&gt;Forem, which is a Ruby on Rails app, integrates the Open API Specification via a gem - the &lt;code&gt;rswag&lt;/code&gt; gem. The &lt;a href="https://github.com/rswag/rswag"&gt;rswag Ruby gem&lt;/a&gt; allows us to create a DSL for describing and testing our API operations. It also extends rspec-rails "request specs", hence, allowing &lt;a href="https://github.com/forem/forem/spec/requests/api/v1/docs/"&gt;our documentation&lt;/a&gt; to be a part of our test suite which allows us to make requests with test parameters and seed data that invoke different response codes. As a result, we are able to test what the requests and responses look like, however we do not test the business logic that drives the endpoint - that is tested elsewhere in the code.&lt;/p&gt;

&lt;p&gt;Once we write the test, we are able to generate a JSON file that conforms to the Open API Specification thus allowing us to eventually use the document generation tools to format and beautify our documentation. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/forem/forem/blob/main/swagger/v1/api_v1.json"&gt;The OpenAPI definition in the form of &lt;code&gt;api_v1.json&lt;/code&gt; is generated&lt;/a&gt; and used as input to Docusaurus to create our documentation. You can view our v1 documentation &lt;a href="https://developers.forem.com/api/v1"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we’ve discussed how Open API and rswag fit together to create the API documentation let’s work through an example of adding documentation to an endpoint together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documenting a v1 endpoint
&lt;/h2&gt;

&lt;p&gt;We’ll be working on this &lt;a href="https://github.com/forem/forem/issues/18744"&gt;github issue&lt;/a&gt; together. The issue outlines a task to use rswag to document the  &lt;code&gt;/api/followers/users&lt;/code&gt; endpoint in the v1 API. &lt;/p&gt;

&lt;p&gt;For reference, our v1 documentation lives &lt;a href="https://github.com/forem/forem/spec/requests/api/v1/docs/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is also a &lt;a href="https://github.com/forem/forem/pull/18965"&gt;pull request&lt;/a&gt; for the code written in the example below which you can reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skeleton
&lt;/h3&gt;

&lt;p&gt;Let’s start by creating a file for the endpoint that we want to test and document.We can go ahead and create &lt;code&gt;spec/requests/api/v1/docs/followers_spec.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There are some building blocks for each test - a skeleton that defines some standards, implementation details like generating the header values, seed data etc.  &lt;/p&gt;

&lt;p&gt;Below is a code snippet of the skeleton for this test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rails_helper"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"swagger_helper"&lt;/span&gt;

&lt;span class="c1"&gt;# rubocop:disable RSpec/EmptyExampleGroup&lt;/span&gt;
&lt;span class="c1"&gt;# rubocop:disable RSpec/VariableName&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Api::V1::Docs::Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
 &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:Accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"application/vnd.forem.api-v1+json"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:api_secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:api_secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:follower1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:follower2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;follower1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;follower2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"GET /followers/users"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"/api/followers/users"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
     &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
     &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# rubocop:enable RSpec/EmptyExampleGroup&lt;/span&gt;
&lt;span class="c1"&gt;# rubocop:enable RSpec/VariableName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start off by importing the necessary libraries - in this case the &lt;code&gt;rails_helper&lt;/code&gt; and the &lt;code&gt;swagger_helper&lt;/code&gt; that will allow us to use the DSL to build out our definitions. &lt;/p&gt;

&lt;p&gt;If you’re use RSpec before then the &lt;code&gt;describe&lt;/code&gt; block will be familiar to you, it will create an example group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:Accept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"application/vnd.forem.api-v1+json"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:api_secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:api_secret&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;Above, we define (but not yet set) the header values. The accept header will allow us to access the v1 API and since the &lt;code&gt;/api/followers/users&lt;/code&gt; endpoint requires authentication we generate an API secret that we will use later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:follower1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:follower2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;follower1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;follower2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above, we use RSpec to setup our data so that we can have example responses in our API documentation. We create a user and two follower users. With these models in the DB rswag will run the tests and display the example tags created by FactoryBot in the json file. In the before block, we then setup the two follows to follow the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"GET /followers/users"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s2"&gt;"/api/followers/users"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
     &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
     &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a nested describe block we start by specifying the path for the endpoint that we’re testing which is &lt;code&gt;/api/followers/users&lt;/code&gt;. You can read more about path operations in the &lt;a href="https://github.com/rswag/rswag#paths-operations-and-responses"&gt;rswag documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In some circumstances, you may have an identifier or parameter in the path. These are surrounded by curly braces. For example: &lt;code&gt;/api/articles/{id}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operation Ids
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is considered our operation block. In this instance we define that we are implementing a GET. &lt;/p&gt;

&lt;p&gt;The Operation Object has several fields that can be set to help define this endpoint. You can read more about &lt;a href="https://swagger.io/specification/#operation-object"&gt;operation objects here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;These are some of the fields that we want to define for &lt;code&gt;api/followers/users&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="s2"&gt;"followers"&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;DESCRIBE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;
  This endpoint allows the client to retrieve a list of the followers they have.
  "Followers" are users that are following other users on the website.
  It supports pagination, each page will contain 80 followers by default.
&lt;/span&gt;&lt;span class="no"&gt;  DESCRIBE&lt;/span&gt;
  &lt;span class="n"&gt;operationId&lt;/span&gt; &lt;span class="s2"&gt;"getFollowers"&lt;/span&gt;
  &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below, I’ve taken some of the definitions from the specification and applied it to the code sample to help explain what each field does. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tags&lt;/strong&gt;: A list of tags for API documentation control. They are used for logical grouping of operations by resources or any other qualifier. In this case, we want this endpoint to be grouped on its own and so we provide it with a new tag. In other circumstances, you may want to tag your crud operations for a single resource all with the same tag so that they can logically group together. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;description&lt;/strong&gt;: Provides a verbose explanation of the operation behavior. CommonMark syntax may be used for rich text representation. We try to describe what the endpoint does in a single sentence. Thereafter, we can provide additional context that we think will be useful to the user of the API at a glance. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;operationId&lt;/strong&gt;: This is a unique string used to identify the operation. The id must be unique among all operations described in the API. The operationId value is case-sensitive. Tools and libraries may use the operationId to uniquely identify an operation, therefore, it is recommended to follow common programming naming conventions. We try to structure the work with the CRUD operation as the prefix and the resource as the suffix. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;produces&lt;/strong&gt;: This field populates the response content type with the &lt;code&gt;produces&lt;/code&gt; property of the OpenAPI definition. Our response type is usually JSON.&lt;/p&gt;

&lt;p&gt;Another noteworthy field that we add to other endpoints but is not relevant to this particular endpoint is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;security&lt;/strong&gt;: This is a declaration of which security mechanisms can be used across the API. Individual operations can override this definition. &lt;/p&gt;

&lt;p&gt;We &lt;a href="https://github.com/forem/forem/blob/main/spec/swagger_helper.rb#L36-L63"&gt;define a security scheme globally in swagger_helper.rb level&lt;/a&gt;&lt;code&gt;security: [{ "api-key": [] }],&lt;/code&gt;. The security scheme that we utilize applies authentication via an api-key header. &lt;/p&gt;

&lt;p&gt;However, remember earlier I mentioned that not all endpoints need authentication. Hence, for those that do not need authentication, we can override the "security" attribute at the operation level. To do this, we provide an empty security requirement ({}) to the array. &lt;/p&gt;

&lt;p&gt;If you look at &lt;a href="https://github.com/forem/forem/blob/main/spec/requests/api/v1/docs/articles_spec.rb#L26"&gt;&lt;code&gt;/api/articles&lt;/code&gt; in the &lt;code&gt;article_spec&lt;/code&gt;&lt;/a&gt; you will see &lt;code&gt;security []&lt;/code&gt; which indicates that this endpoint does not need authentication.&lt;/p&gt;

&lt;p&gt;However, in the case of the endpoint that we’re documenting &lt;code&gt;/api/followers/users&lt;/code&gt; we do not need to provide a security field as we’ll use the one that is defined globally with the API key for authentication via an api key. &lt;/p&gt;

&lt;p&gt;Now that we’ve set these operationIds, let’s have a look at how they would get generated in the JSON file. &lt;/p&gt;

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

&lt;p&gt;The operationIds set the scene for how the API operates. Next, we’ll want to define the parameters that the API endpoint allows.  &lt;/p&gt;

&lt;p&gt;The following two sections, Parameters and Response Blocks, rely on &lt;strong&gt;schemas&lt;/strong&gt;, so before we get into the details of these sections let’s first discuss what a schema is.&lt;/p&gt;

&lt;p&gt;The OpenAPI Specification allows you to describe something called a "schema" which in its simplest form refers to some JSON structure. These can be defined either inline with your operation descriptions OR as referenced globals.&lt;/p&gt;

&lt;p&gt;You can use a referenced global when you have a repeating schema in multiple operation specs. For example, an article resource may be returned in a create, read or update, hence instead of repeating this JSON across all these operations you could add it as a referenced global in the swagger_heper.rb and then use that &lt;code&gt;$ref&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The global definitions section lets you define common data structures used in your API. They can be referenced via &lt;code&gt;$ref&lt;/code&gt;: "a schema object" – both for request body and response body. &lt;/p&gt;

&lt;p&gt;Another instance where you may want to use a referenced global is when multiple endpoints accept the same parameter schema and you do not want to repeat this JSON for multiple endpoints. &lt;/p&gt;

&lt;h3&gt;
  
  
  Parameters
&lt;/h3&gt;

&lt;p&gt;If you look at the &lt;a href="https://github.com/forem/forem/blob/main/app/controllers/concerns/api/followers_controller.rb"&gt;code for the &lt;code&gt;api/followers/users&lt;/code&gt; endpoint&lt;/a&gt;, you’ll notice that it takes three optional parameters; &lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt; and &lt;code&gt;sort&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;You’ll notice that we use &lt;code&gt;page&lt;/code&gt; and &lt;code&gt;per_page&lt;/code&gt; across multiple endpoints for our pagination strategy hence that reusability makes it the ideal candidate for a referenced global. &lt;/p&gt;

&lt;p&gt;Since it’s been used before, you’ll find it &lt;a href="https://github.com/forem/forem/blob/main/spec/swagger_helper.rb#L64-L157"&gt;defined globally in the &lt;code&gt;swagger_helper.rb&lt;/code&gt;&lt;/a&gt;. Hence, all we need to do is reference it in our spec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="s2"&gt;"$ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"#/components/parameters/pageParam"&lt;/span&gt;
&lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="s2"&gt;"$ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"#/components/parameters/perPageParam30to1000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, our next parameter - &lt;code&gt;sort&lt;/code&gt;, has not been defined before and does not seem to be re-used in the same manner across any existing endpoints. Thus we can define it inline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="ss"&gt;name: :sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;in: :query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;required: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"Default is 'created_at'. Specifies the sort order for the created_at param of the follow
                               relationship. To sort by newest followers first (descending order) specify
                               ?sort=-created_at."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="ss"&gt;schema: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="ss"&gt;example: &lt;/span&gt;&lt;span class="s2"&gt;"created_at"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can read more about describing query parameters in the OpenAPI Guide &lt;a href="https://swagger.io/docs/specification/describing-parameters/#query-parameters"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what the final set of query parameters look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"Followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;......&lt;/span&gt;
  &lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="s2"&gt;"$ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"#/components/parameters/pageParam"&lt;/span&gt;
  &lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="s2"&gt;"$ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"#/components/parameters/perPageParam30to1000"&lt;/span&gt;
  &lt;span class="n"&gt;parameter&lt;/span&gt; &lt;span class="ss"&gt;name: :sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;in: :query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;required: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"Default is 'created_at'. Specifies the sort order for the created_at param of the follow
                               relationship. To sort by newest followers first (descending order) specify
                               ?sort=-created_at."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="ss"&gt;schema: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="ss"&gt;example: &lt;/span&gt;&lt;span class="s2"&gt;"created_at"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what the corresponding generated JSON would look like:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Response Blocks
&lt;/h3&gt;

&lt;p&gt;Once we’ve defined the operation Ids and Parameters, we can define what the response query looks like. We can create multiple response blocks in order to test the various responses a user of the API may receive. This includes testing when the API endpoint provides a response, when there is no content, when the user is not authorized etc. &lt;/p&gt;

&lt;p&gt;In this case, we’ll test what a successful response looks like and what an unauthorized response looks like when we do not provide the correct api-key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A successful response with status code 200&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"A List of followers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:"api-key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="ss"&gt;type: :array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;items: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"A user (follower)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="ss"&gt;type_of: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"user_follower by default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;format: :int32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"The follower's user id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;format: :int32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"The follower's name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"A path to the follower's profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;profile_image: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"Profile image (640x640)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="n"&gt;add_examples&lt;/span&gt;


   &lt;span class="n"&gt;run_test!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200"&gt;HTTP 200 OK success status response code&lt;/a&gt; indicates that the request has succeeded.&lt;/p&gt;

&lt;p&gt;In order for the request to succeed, we first need to provide the necessary authentication. When this example runs, it will need the &lt;code&gt;api-key&lt;/code&gt; for authentication, hence we set it in our RSpec test. &lt;/p&gt;

&lt;p&gt;In this case, I’ve decided to define the schema object inline because it is a uniquely structured response that is not being shared with other endpoints. However, if more than one endpoint had the same schema it would have been beneficial to define it globally in the swagger_helper and then provide a reference to it in the various spec files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="ss"&gt;type: :array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;items: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"A user (follower)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="ss"&gt;properties: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="ss"&gt;type_of: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"user_follower by default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;type: :integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;format: :int32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"The follower's user id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;format: :int32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"The follower's name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"A path to the follower's profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
             &lt;span class="ss"&gt;profile_image: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"Profile image (640x640)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :string&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;The schema that we have defined above is an array of objects. The top level type is defined by an array type and each item is an object. Thereafter, we further define the properties that can be expected in each object. We advise that a description for a property is added where necessary. &lt;/p&gt;

&lt;p&gt;If the need to re-use the schema object for multiple endpoints arose, we could have defined it as a &lt;code&gt;Follower&lt;/code&gt; in the &lt;code&gt;swagger_helper.spec&lt;/code&gt; and then referenced it in our spec like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="ss"&gt;type: :array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;items: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"$ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"#/components/schemas/Follower"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;add_examples&lt;/code&gt; method can be found in the &lt;a href="https://github.com/forem/forem/blob/f105d6a8f55705b08b380531fd34029301617465/spec/swagger_helper.rb#L273-L274"&gt;swagger_helper&lt;/a&gt; and it is responsible for creating the &lt;a href="https://swagger.io/specification/#responseObject"&gt;Response Object&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It creates a map containing descriptions of potential response payloads.&lt;br&gt;
The key is a media type or media type range like &lt;code&gt;application/json&lt;/code&gt; and the value describes it. &lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;run_test!&lt;/code&gt; method is called within each response block. This tells rswag to create and execute a corresponding example. It builds and submits a request based on parameter descriptions and corresponding values that have been provided using the rspec "let" syntax. In order for our examples to add value, we want to give it a good set of seed data.&lt;/p&gt;

&lt;p&gt;If you want to do additional validation on the response, you can pass a block to the run_test! method. &lt;/p&gt;

&lt;p&gt;You can read more about how to use run_test! from the &lt;a href="https://github.com/rswag/rswag#paths-operations-and-responses"&gt;rswag documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An unauthorized response with status code 401&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="s2"&gt;"401"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"unauthorized"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:"api-key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;add_examples&lt;/span&gt;

  &lt;span class="n"&gt;run_test!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The HyperText Transfer Protocol (HTTP) &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401"&gt;401 Unauthorized response status code&lt;/a&gt; indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource. Hence, in this case if we provide an invalid api key, we should expect a 401. &lt;/p&gt;

&lt;p&gt;To test this case, we simply provide an invalid API key which will not allow us to authenticate to the API.&lt;/p&gt;

&lt;p&gt;The generated JSON for these two responses look as follows:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Generating the JSON
&lt;/h2&gt;

&lt;p&gt;I’ve been referencing the JSON files above, but you must be wondering how do you access that JSON. Once you have written your spec, you can generate the JSON file for the API by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SWAGGER_DRY_RUN=0 RAILS_ENV=test rails rswag PATTERN="spec/requests/api/v1/**/*_spec.rb"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you do this, you will see a newly generate file at &lt;a href="https://github.com/forem/forem/blob/main/swagger/v1/api_v1.json"&gt;https://github.com/forem/forem/blob/main/swagger/v1/api_v1.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Take the time to evaluate the generated content in this file, especially for the new spec. In order to view it you may paste the JSON into &lt;a href="https://editor.swagger.io/"&gt;https://editor.swagger.io/&lt;/a&gt;. When you do this, it will display the data as documentation and also let you know if there are any errors. &lt;/p&gt;

&lt;p&gt;If you have Visual Studio Code, we suggest you install the following extensions that enable validation and navigation within the spec file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi"&gt;OpenAPI (Swagger) editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=philosowaffle.openapi-designer"&gt;openapi-designer live preview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that, my friends, is how we document API v1 endpoints at Forem. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/lD76yTC5zxZPG/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/lD76yTC5zxZPG/giphy.gif" alt="That's all folks" width="499" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the code for this example &lt;a href="https://github.com/forem/forem/pull/18965"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, please drop them in the comments below. &lt;strong&gt;If you’d like to contribute to our documentation please have a look through the ones that aren’t assigned in this &lt;a href="https://github.com/forem/forem/milestone/10"&gt;milestone&lt;/a&gt; and raise your hand on the issue.&lt;/strong&gt; We look forward to your contributions. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>documentation</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Destructuring in Ruby</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Wed, 03 Aug 2022 09:46:00 +0000</pubDate>
      <link>https://dev.to/ridhwana/destructuring-in-ruby-53j0</link>
      <guid>https://dev.to/ridhwana/destructuring-in-ruby-53j0</guid>
      <description>&lt;p&gt;Destructuring refers to the process of unpacking a small part of something from the main part. In Ruby, we use destructuring to conveniently extract multiple values from data stored in Arrays or Hashes. It provides a way for us to group or ungroup data and assign them to variables where needed. &lt;/p&gt;

&lt;p&gt;In this article we’re going to discuss destructuring for assignments, arrays and keyword args. We’ll also touch on why you would utilize destructuring.&lt;/p&gt;

&lt;p&gt;The most straightforward form of destructuring is through multiple assignments. This form of destructuring assigns the variables on the left to the values on the right in the order that they are provided. &lt;/p&gt;

&lt;p&gt;As an example: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; 
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; 


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

&lt;/div&gt;

&lt;p&gt;In the above example the variables on the left are assigned to the values on the right. If we have a mismatch between the number of variables ready for assignment on the left and the number of values on the right then some of the variables will remain unassigned like below: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; 
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; 
&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="sb"&gt;`d' for main:Object
```&lt;/span&gt;

&lt;span class="no"&gt;If&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;mismatch&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;fewer&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;assign&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;them&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;remain&lt;/span&gt; &lt;span class="n"&gt;unassigned&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="ss"&gt;below: 

&lt;/span&gt;&lt;span class="sb"&gt;```ruby
a, b, c = 1, 2, 3, 4

a =&amp;gt; 1 
b =&amp;gt; 2 
c =&amp;gt; 3 
```&lt;/span&gt;

&lt;span class="no"&gt;More&lt;/span&gt; &lt;span class="n"&gt;complex&lt;/span&gt; &lt;span class="n"&gt;destructuring&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="no"&gt;Ruby&lt;/span&gt; &lt;span class="n"&gt;called&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;splat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Splat&lt;/span&gt; &lt;span class="n"&gt;performs&lt;/span&gt; &lt;span class="n"&gt;different&lt;/span&gt; &lt;span class="n"&gt;operations&lt;/span&gt; &lt;span class="n"&gt;depending&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;discuss&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt; &lt;span class="n"&gt;splat&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; 

&lt;span class="c1"&gt;## Slurp/Collect&lt;/span&gt;

&lt;span class="no"&gt;When&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;splat&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="n"&gt;appears&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;hand&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;refer&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;slurp&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Slurping&lt;/span&gt; &lt;span class="n"&gt;takes&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;collects&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="no"&gt;The&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="n"&gt;below&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slurp&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;collect&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;assigned&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="ss"&gt;variables: 

&lt;/span&gt;&lt;span class="sb"&gt;```ruby
a, b, *c = 1, 2, 3, 4

a =&amp;gt; 1 
b =&amp;gt; 2 
c =&amp;gt; [3, 4]
```&lt;/span&gt;

&lt;span class="no"&gt;Splat&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;pretty&lt;/span&gt; &lt;span class="n"&gt;smart&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;slurp&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;depending&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;splat&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;positioned&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Let&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;look&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nf"&gt;`&lt;/span&gt;&lt;span class="sb"&gt;``&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="sb"&gt;```

A splat operator *somewhere in the middle* will get the “rest” of the values once the other non-splatted variables are assigned. In this case, `&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="sb"&gt;` gets assigned to the first value, then `&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="sb"&gt;` gets assigned to the last value and `&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="sb"&gt;` gets assigned the remainder of the values in the form of an array. 

Now, think about what you would expect a *slurp operator on a  variable at the start* of the assignment to yield?

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="sb"&gt;```

Well, we’d look at the non splatted values first and work our way backwards - `&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="sb"&gt;` will take the value of 4, `&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="sb"&gt;` will take the value of 3 and `&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="sb"&gt;` would collect the “rest” of the values into an array i.e. `&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="sb"&gt;`. Does that make sense to you? 

Just like above, an array can also be destructured into multiple parts and assigned to variables.

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="sb"&gt;```

## Split

Up until now we talked about a splat on the left hand side of the assignment which slurps or collects up the values on the right hand side. How does it then work when the splat operator (*) is on the right hand side? It will split up the array into individual components. 

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; 
&lt;span class="sb"&gt;```

Destructuring on the right hand side allows us to split the collection into a list of values being assigned. 

So in the case above the splat on `&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="sb"&gt;` will change the statement into:

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="sb"&gt;```

and so the assignments happen as per usual: 

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="sb"&gt;```

Let’s look at a more complex example - what if we had to split on the right side of the assignment and slurp up values on the left side, how would that work?

## Slurp and Split

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;
&lt;span class="sb"&gt;```

You’re already equipped with the tools for dealing with them separately so let’s apply that knowledge. 

First, let’s look at the right side of this assignment. Based on previous knowledge we know that the splat operator on the right hand side will split, meaning that it will convert the array into a list of values like below: 

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; 
&lt;span class="sb"&gt;```

Now that we’ve done that, let's look at the left hand side of the assignment. As per the rules that we learned earlier, we will allocate the first variable `&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="sb"&gt;` to the first value `&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="sb"&gt;`. We have the splat in the middle so let's leave that for last. We then allocate out the last variable to the last value, so `&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="sb"&gt;` is assigned to `&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="sb"&gt;`. Finally, we’ll focus on the splat operator which indicates that we should slurp up the rest of the values `&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="sb"&gt;` to assign to `&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="sb"&gt;`.

## Implicit and Explicit Splats

If we have an assignment containing just one variable on the left with a number of values on the right, it will slurp up all of the values into a new array.

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="sb"&gt;```
This is equivalent to 

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="sb"&gt;```

Notice that in the first example we didn’t need the asterisk, the value was just *implicitly spatted*. In some cases where the assignments are more straightforward, this is acceptable.  

However, if you wanted to perform destructuring where there is more than one variable on the left you would need to explicitly splat the variable. You would also have noticed in some of the above sections that there are cases whereby an array will be listed alongside individual values, and hence you would need an explicit splat to break down the array into its component values.

## Keyword Arguments 

In a rails app you’ll often come across a splat on argument methods, like `&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="sb"&gt;` below:

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"hello &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
 &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
   &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"hello &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Goofy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Donald Duck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Fred Flinstone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Pluto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;Goofy&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;Donald&lt;/span&gt; &lt;span class="no"&gt;Duck&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;Fred&lt;/span&gt; &lt;span class="no"&gt;Flinstone&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;Pluto&lt;/span&gt;
&lt;span class="sb"&gt;```

Abiding to our previous rules outlined, the splat operator on `&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="sb"&gt;`  collects the rest of the parameters except the one assigned to `&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="sb"&gt;`. It then converts those “rest” of the arguments to an array within the method, hence, allowing us to loop through the args.

In this manner, we don’t need to specify the number of arguments that we are providing to the method. Instead, we can deal with them as an array that we loop through.

The parameter with the splat operator is also optional, which means that if we omit these arguments to a method, Ruby will not complain about it. 

```&lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;
&lt;span class="n"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Goofy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Donald Duck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Fred Flinstone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Pluto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;Goofy&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="sb"&gt;```

It is important to note that a method cannot have two parameters with a splat operator, and you can only splat the last parameter to a method. 

Now that we’ve got a good foundation on how destructuring is used, let’s talk about when we would use destructuring.

## Use Cases

Destructuring can be used: 
- When you do not want to specify the number of parameters that you have.
- When you want to make the parameter optional - a parameter with a splat operator is optional. 
- When you’d like to convert a list of arguments to an array within the method and vice versa - when you want to convert an array into several arguments.. 
- You can use destructuring when programming in a functional, recursive manner whereby you can assign the first parameter to one variable and the rest of the variables can be assigned to another variable using a splat. 

The scenarios above are only some instances where destructuring can be useful, let me know how you’ve used destructuring in the past.


![Cut a slice of cake gif](https://media.giphy.com/media/xUPGcCM0nd2A4sIuaY/giphy.gif)

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

&lt;/div&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Getting Oriented with Objects in Ruby</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Wed, 08 Jun 2022 17:06:55 +0000</pubDate>
      <link>https://dev.to/ridhwana/getting-oriented-with-objects-in-ruby-2h44</link>
      <guid>https://dev.to/ridhwana/getting-oriented-with-objects-in-ruby-2h44</guid>
      <description>&lt;p&gt;This post is co-authored by &lt;a class="mentioned-user" href="https://dev.to/juliannatetreault"&gt;@juliannatetreault&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/ridhwana"&gt;@ridhwana&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our last &lt;a href="https://dev.to/ridhwana/introducing-rediscovering-ruby-53bk"&gt;post&lt;/a&gt; we briefly touched upon a few topics such as: object orientation, dynamic languages and memory management. However, we barely scratched the surface of these concepts, and so in this post, we’d like to dive deeper into object orientation and how it all comes together in Ruby. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby Objects
&lt;/h2&gt;

&lt;p&gt;As we mentioned in our previous post, Ruby is centered around the concept of “objects”. Everything in Ruby is an object - this includes Booleans, Strings, Integers and more. &lt;/p&gt;

&lt;p&gt;A Ruby Object will contain its own set of attributes, which you can think of as data, and its own set of methods, which you can think of as the behaviour. &lt;/p&gt;

&lt;p&gt;Ruby Objects communicate by sending messages to each other. These messages can be thought of as instructions. When we talk about “sending a message from Object A to Object B”, what we actually mean is that we “call or invoke a method on Object B”. These terms can be used interchangeably. &lt;/p&gt;

&lt;p&gt;If you take a second to look up from reading this article and glance around your surroundings, you’ll see that there are objects everywhere in the world. &lt;/p&gt;

&lt;p&gt;As I look up at this moment, I see -  my 😼, a 🪴, a 📘, a 🖨 and a 🛋 are some of the objects that jump out to me. All of these have the potential to be modelled as Objects each with its own data and behaviour, and sometimes these objects send messages to each other, like when my cat chews on a leaf from my plant. &lt;/p&gt;

&lt;p&gt;Some of the concepts that we’ll need to discuss first before fully understanding Ruby objects are classes, attributes and methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Class?
&lt;/h2&gt;

&lt;p&gt;A Class is a blueprint for the construction of similar objects - you can think of it as a template that we use to create objects. The template provides the set of attributes and methods for an object, which will then help each object to define its own set of data and shared behaviour.   &lt;/p&gt;

&lt;p&gt;For example, we may want to represent my cat. In order to do this, we’d first create a blueprint that we could use to represent all cats. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Below we represent the Class-y Cat, haha get it?&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;This blueprint will contain the attributes that a cat may have like name, age, colour and weight. It will also contain behaviour like the sound that a cat will make or how it will move its tail. In the future, we may want our blueprint to be more general, so we may want to make an Animal blueprint and use it to create both a cat and a dog object - but that’s for later. &lt;/p&gt;

&lt;p&gt;In reality, the code for the Cat Class may look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; 
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
    &lt;span class="vi"&gt;@age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
    &lt;span class="vi"&gt;@colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;colour&lt;/span&gt;
    &lt;span class="vi"&gt;@weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"meow"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;move_tail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"twitching"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to describe my cat, we would use this template to instantiate a new object. In Ruby the new method is used for instantiating an object. This now creates my object as an instance of the &lt;code&gt;Cat&lt;/code&gt; Class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;zeus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Zeus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"brown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this may not make sense to you as yet, but let’s break down the code above by describing the attributes and methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attributes (Data)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, &lt;code&gt;colour&lt;/code&gt; and &lt;code&gt;weight&lt;/code&gt; in the parenthesis are referred to as parameters. They describe the characteristics of the object.&lt;/p&gt;

&lt;p&gt;When we instantiate an object, like in the code below, we pass through the values for these parameters in the form of arguments. The arguments are what allow us to provide specific values for that object. &lt;/p&gt;

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

&lt;p&gt;When we call the method &lt;code&gt;new&lt;/code&gt; on a class, the class will create a new instance of itself. Internally, it then calls the method &lt;code&gt;initialize&lt;/code&gt; on the new object, and it will pass all the arguments to the method &lt;code&gt;initialize&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; method as outlined in the image above is then responsible for preparing the instance data for the object. &lt;code&gt;@name&lt;/code&gt;, &lt;code&gt;@age&lt;/code&gt;, &lt;code&gt;@color&lt;/code&gt; and &lt;code&gt;@weight&lt;/code&gt; are referred to as instance variables - they can be identified by the &lt;code&gt;@&lt;/code&gt; prefix. Instance variable data is unique to the object.&lt;/p&gt;

&lt;p&gt;Instance variables by default cannot be accessed from outside the object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;zeus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Zeus&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;brown&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="n"&gt;zeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;NoMethodError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="sb"&gt;`age`&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi11yg2831ghbsx7dn5n6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi11yg2831ghbsx7dn5n6.jpg" alt="OMG Cat" width="147" height="97"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;But what if we really need to print out Zeus’s age from outside?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, there are definitely times when we may want to access (read and write) these instance variables from the outside. In these cases we can access the attributes with attribute accessors. &lt;/p&gt;

&lt;p&gt;There are three attribute accessors that we will discuss:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;attribute_reader&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to be able to read an attribute from the outside without the need to change it then you can use an &lt;code&gt;attribute_reader&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;
  &lt;span class="n"&gt;attribute_reader&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt;

  &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you add &lt;code&gt;attribute_reader&lt;/code&gt; to your code, Ruby then creates a method on your behalf that looks like the code below, and allows you to read the attribute. The symbol for the attribute_reader is used as the name for this getter_method as defined below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;age&lt;/span&gt;
    &lt;span class="vi"&gt;@age&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;zeus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Zeus&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;brown&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="n"&gt;zeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll learn more about methods in the next section. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;attribute_writer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Likewise, in order to be able to write to an attribute from the outside then you can use an &lt;code&gt;attribute_writer&lt;/code&gt;. Just like with &lt;code&gt;attribute_reader&lt;/code&gt; Ruby then creates a method on your behalf that looks like the code below, and allows you to write to the attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;zeus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Zeus&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;brown&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="no"&gt;Zeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;attribute_accessor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to be able to both read and write to an attribute, we would use &lt;code&gt;attr_accesor&lt;/code&gt;. Ruby then creates both methods on your behalf. &lt;/p&gt;

&lt;p&gt;Now that we’ve discussed attributes, let’s talk about methods. &lt;/p&gt;

&lt;h3&gt;
  
  
  Behaviour (Methods)
&lt;/h3&gt;

&lt;p&gt;Methods allow you to bundle code that can perform tasks and return results in a named, DRY (don’t repeat yourself!) way. Methods can be called from other code, allowing programmers to use the bundled code without having to rewrite it in every place it’s needed.&lt;/p&gt;

&lt;p&gt;When it comes to crafting a method, there are a few things you should know about them: &lt;/p&gt;

&lt;p&gt;First, methods are defined using the &lt;code&gt;def&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; keywords. &lt;code&gt;def&lt;/code&gt;, followed by a name, represents the start of a method. The &lt;code&gt;end&lt;/code&gt; keyword does just that – it ends the method. What comes in between the &lt;code&gt;def&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; keywords is the bundled code or logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_name&lt;/span&gt;
   &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;behaviour&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, methods have their own set of naming conventions. When creating a method, it is important to keep these naming conventions in mind, as it’ll make it easier to understand the intent of the method for the next programmer (or you, 6 months down the road!). The naming conventions we’d like to draw your attention to are: naming your method, the capitalization of your method, and what to do when your method name is longer than a single word.&lt;/p&gt;

&lt;p&gt;Let’s begin with naming your method. When brainstorming method name ideas, it is important to ensure that the method is aptly named – the method’s name should be explanatory, giving insight into the method’s purpose. If you’re creating a method that will give your &lt;code&gt;Cat&lt;/code&gt; Object the ability to meow, then naming the method &lt;code&gt;meow&lt;/code&gt; is a good place to start. Now let’s touch upon method capitalization, or the lack thereof. Method names should consist of all lowercase letters. Finally, let’s discuss what to do when your method name is longer than a single word. Multi-word method names in Ruby are written in snake case. For example, if you had a method that both made your &lt;code&gt;Cat&lt;/code&gt; Object meow and move its tail, you might write it as &lt;code&gt;meow_and_move_tail&lt;/code&gt;, where the underscores between each word represent snake casing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;meow_and_move_tail&lt;/span&gt;
   &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;behaviour&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the logic within a method is always indented. The rule of thumb when it comes to indentation is four spaces or a tab to the right. While there is an ongoing feud within the programming community about which approach is right (hint: neither are!), it all boils down to preference. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tabs or spaces - which side are you on?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the topic of crafting methods, one thing that is important to mention is that methods can accept default arguments and values, which can level up your method and make it more reusable. A default argument allows a method to be called with or without the provided argument, allowing for flexibility. It also gives you the option to reassign the value passed to the default argument, making the method more extensible. To pass a method a default argument with an assigned value, open a set of parentheses after the method name and define the argument and its value like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Meow&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;behaviour&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above &lt;code&gt;make_sound&lt;/code&gt; method, we pass a default argument &lt;code&gt;sound&lt;/code&gt;, with the value &lt;code&gt;meow&lt;/code&gt;. By passing this default argument, if we were to lean on the default argument in the method’s logic, we could expect that the string “Meow” would be returned whenever the method is called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Meow&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{sound}!”&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you may be wondering what those squiggly brackets and hashtag are doing within the &lt;code&gt;make_sound&lt;/code&gt; method–the use of this is called string interpolation, which can briefly be explained as embedding the value within the string that it is a part of. This is something we may touch upon in a later post, so stay tuned, folks!&lt;/p&gt;

&lt;p&gt;Similar to default arguments, methods can also accept required parameters. While default arguments and values are optional, required parameters are just that - required. Just like default arguments, required parameters are defined within a set of parentheses that come right after a method’s name. Unlike default arguments though, a required parameter is not given a default value, rather its value is defined when the method is invoked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{sound}!”&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Purr&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, method naming conventions, default arguments, and string interpolation aside, let’s briefly touch upon CRUD actions, or the widely used methods standard to Ruby. CRUD, which stands for &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt;, are a set of methods provided in Ruby that perform basic actions such as creating, reading, updating, or deleting an Object. These methods are important to recognize due to their wide use.&lt;/p&gt;

&lt;p&gt;Now, with all of this new-found knowledge of methods, you may be wondering how to actually make use of this behaviour. If so, then this paragraph is for you! We refer to making use of a method’s behaviour as “invoking” or “calling” a method in Ruby. This can be accomplished using dot notation, which when used, invokes a method, passing along a message to an Object, which in our case, is our &lt;code&gt;Cat&lt;/code&gt;, Zeus. &lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;Is that really all there is to methods?! Seems pretty straightforward to me…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The above is just the beginning and while there is so much more to learn about methods, knowing the above should get you to a good baseline understanding of how Objects are given behaviour and receive messages through methods. If you’re keen to dive a bit deeper though, we’ll be releasing a brief follow up post that will touch upon some of the topics that didn’t make it into this post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And that’s it folks…&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Credits to &lt;a class="mentioned-user" href="https://dev.to/juliannatetreault"&gt;@juliannatetreault&lt;/a&gt; for the adorable cat drawings. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>ruby</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing Rediscovering Ruby</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Mon, 23 May 2022 16:38:35 +0000</pubDate>
      <link>https://dev.to/ridhwana/introducing-rediscovering-ruby-53bk</link>
      <guid>https://dev.to/ridhwana/introducing-rediscovering-ruby-53bk</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is co-authored by &lt;a class="mentioned-user" href="https://dev.to/juliannatetreault"&gt;@juliannatetreault&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/ridhwana"&gt;@ridhwana&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

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

&lt;p&gt;👋 Hi there and welcome to the first post in our series, &lt;strong&gt;Rediscovering Ruby&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My name is Julianna. I’m a primarily backend-focused Software Engineer at Forem and I have been working with Ruby and Rails, almost exclusively, for roughly 3 years now and I still learn new things about Ruby almost daily. &lt;/p&gt;

&lt;p&gt;My name is Ridhwana and I’m a Full Stack Lead Software engineer at Forem. I’ve been dabbling in Ruby on Rails for about 8-10 years and spent just under half of that time focussing on backend development which has been leading me through weird and wonderful explorations in this language. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why are we writing this series?
&lt;/h2&gt;

&lt;p&gt;We’ve been working together for a while now and thoroughly enjoy it. We often find ourselves talking through Ruby concepts or pair programming asynchronously through pull request reviews. We’ve realized that a lot of developers (including ourselves) end up learning a new language by exploring and copying existing patterns within an already existing codebase. This sometimes leaves us without a name for a pattern that we’re following or without a deeper understanding of what's happening behind the “magic” of the language. It also means that sometimes we struggle to articulate concepts that we use on a daily basis.  &lt;/p&gt;

&lt;p&gt;Hence, we came up with an idea to write a series of posts that explore and explain these different concepts in Ruby. We hope that you’ll follow along and share your knowledge and experiences with us too. &lt;/p&gt;

&lt;h2&gt;
  
  
  What do we plan on covering in this series?
&lt;/h2&gt;

&lt;p&gt;First, we’ll begin with the basics–foundational concepts and the like. While the rest of our plan is still a bit up in the air, after covering some of the core Ruby concepts, we plan to slowly start introducing more complex topics. Some of the concepts and topics that we hope to cover include: classes, objects, memory, and duck-typing.&lt;/p&gt;

&lt;p&gt;With that being said, let's dive into an introduction of our favourite language Ruby.  &lt;/p&gt;




&lt;h2&gt;
  
  
  About Ruby
&lt;/h2&gt;

&lt;p&gt;Ruby was conceived in 1993 and publicly released in 1995 by its creator &lt;a href="http://www.rubyist.net/~matz/"&gt;Yukihiro “Matz” Matsumoto&lt;/a&gt;. It's approximately ~27 years old already!&lt;/p&gt;

&lt;p&gt;Over the years, Matz, Ruby’s creator, can be found talking about some of his motivations for creating Ruby. Some of these include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blending parts of his favorite languages at the time like Perl, Smalltalk, Ada and Lisp etc. into a better object-oriented version, Ruby.&lt;/li&gt;
&lt;li&gt;In a Google talk in 2008 he told the audience that he hoped to see Ruby help every programmer in the world to be productive, and to enjoy programming, and to be happy. He also jokes that he created Ruby for selfish reasons because he was so underwhelmed by other languages that he just wanted to create something that would make him happy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shortly after the release of Ruby, interest in the language quickly grew in Japan. In 2000, the first English-language book “Programming Ruby” was released by author Dave Thomas. This helped to spread the language internationally, and by 2006 Ruby had become popular worldwide. However, after the release of the Ruby on Rails framework the community grew even bigger.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ruby Community
&lt;/h2&gt;

&lt;p&gt;As mentioned above, Ruby has been around for a while, and so has the community that supports the language. The Ruby community has a reputation for being welcoming and supportive, which is one of the reasons why the language is often suggested for beginners. &lt;/p&gt;

&lt;p&gt;If conferences or meetups are your thing (or if you’d like them to be!), Ruby has a plethora of in-person and more recently, remote events. Additionally, due to the age of the language and the size of the community, there are many opportunities to contribute to Open Source projects that use Ruby as their foundation and there are many learning resources available (like this one! :)) for when you want to better acquaint yourself with the language’s intricacies. &lt;/p&gt;

&lt;h2&gt;
  
  
  A Ruby Primer
&lt;/h2&gt;

&lt;p&gt;Ruby can be described as “Object Oriented and Dynamic language.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What exactly does object oriented mean?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This means the language is centered around the concept of “objects.” Hence, in order to write useful applications in an OO language, the code will contain a group of objects. Each object will have its own set of attributes and methods, and these objects will send and react to messages from the other objects. .&lt;/p&gt;

&lt;p&gt;In order to understand what is a “dynamic language'' let's get two definitions out of the way - compile time and run-time?&lt;/p&gt;

&lt;p&gt;Compile-time is the time at which the source code is converted into an executable code. &lt;br&gt;
Run time is the time at which the executable code has started running.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Knowing the above, what does this have to do with a dynamic language?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, a dynamic language gives us the ability to carry out certain actions at runtime that other languages cannot, such as assigning and reassigning objects without running into compiler-related issues. &lt;/p&gt;

&lt;p&gt;In addition, if any errors occur during compile-time, the process will not be halted by those errors and will continue to move forward. For example: If we were to call a method on an object that does not exist, the compiler will not produce a warning or an error. Only once the code is executed will we see a NoMethodError.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Okay, so we’ve discussed what an object-oriented and dynamic language means – is there anything else that sets Ruby aside that I should be aware of?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When it comes to memory allocation and deallocation, Ruby is one of those languages that handles it for you. Memory allocation and deallocation is baked into the language so that, for the most part, you don’t have to think about how to allocate and deallocate memory on a day-to-day basis–this is handled by Ruby garbage collection. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;…garbage collection?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are entire books written and countless talks given on Ruby’s garbage collection mechanism, but a concise explanation for just what Ruby garbage collection is, is that it’s a mechanism within Ruby that handles memory usage–both allocation and deallocation. Ruby provides an interface for its garbage collection so that, in the event that you need to adjust memory usage (or if you’re just curious like us!), then you can see just what’s going on under the hood.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And that’s it folks…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We hope that this post piqued your interest, as we’ll be diving deeper into some of these concepts in upcoming posts. Thank you for reading!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mask and unmask a password input</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Wed, 30 Jun 2021 10:09:49 +0000</pubDate>
      <link>https://dev.to/ridhwana/mask-and-unmask-a-password-input-3lf3</link>
      <guid>https://dev.to/ridhwana/mask-and-unmask-a-password-input-3lf3</guid>
      <description>&lt;p&gt;I recently worked on a feature to be able to mask and unmask a password using some vanilla javascript, and I thought I'd share how I did this.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F2786819%2F123863212-96b0fc80-d929-11eb-92ed-7f70e27a1c85.gif" 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%2Fuser-images.githubusercontent.com%2F2786819%2F123863212-96b0fc80-d929-11eb-92ed-7f70e27a1c85.gif" alt="Password Mask"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to jump ahead and just see the code without the walkthrough, you can view the code on &lt;a href="https://codepen.io/Ridhwana/pen/vYmBrbx" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1:
&lt;/h1&gt;

&lt;p&gt;THE HTML: &lt;/p&gt;

&lt;p&gt;Let's put some HTML together for a password field. In most instances that will form as part of a &lt;code&gt;form&lt;/code&gt; but in this case I'm just going to go ahead and only show the &lt;code&gt;div&lt;/code&gt;  for the password.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Password&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"password-input-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"eye-container js-password-visibility-toggle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"js-eye"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"22"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 22 18"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M11 0c5.392 0 9.878 3.88 10.819 9-.94 5.12-5.427 9-10.82 9C5.609 18 1.123 14.12.182 9 1.12 3.88 5.608 0 11 0zm0 16a9.005 9.005 0 0 0 8.777-7A9.005 9.005 0 0 0 2.223 9 9.005 9.005 0 0 0 11 16zm0-2.5a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9zm0-2a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"#64707D"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"js-eye-off hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"22"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"22"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 22 22"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M16.882 18.297A10.95 10.95 0 0 1 11 20C5.608 20 1.122 16.12.18 11a10.982 10.982 0 0 1 3.34-6.066L.393 1.808 1.807.393l19.799 19.8-1.415 1.414-3.31-3.31zM4.935 6.35A8.965 8.965 0 0 0 2.223 11a9.006 9.006 0 0 0 13.2 5.838l-2.027-2.028A4.5 4.5 0 0 1 7.19 8.604L4.935 6.35zm6.979 6.978-3.242-3.242a2.5 2.5 0 0 0 3.24 3.241l.002.001zm7.893 2.264-1.431-1.43a8.936 8.936 0 0 0 1.4-3.162A9.006 9.006 0 0 0 8.553 4.338L6.974 2.76C8.22 2.27 9.58 2 11 2c5.392 0 9.878 3.88 10.819 9a10.95 10.95 0 0 1-2.012 4.592zm-9.084-9.084a4.5 4.5 0 0 1 4.769 4.77l-4.77-4.77z"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"#64707D"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"js-password"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The  main element to take note of is the &lt;code&gt;password-input-container&lt;/code&gt;. It contains two elements: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;eye-container&lt;/code&gt; with two spans that each contain an SVG (an &lt;code&gt;eye&lt;/code&gt; and an &lt;code&gt;eye-off&lt;/code&gt; SVG). The &lt;code&gt;eye-off&lt;/code&gt; SVG will be hidden by default because the password is masked in its default state.&lt;/li&gt;
&lt;li&gt;An input field with type &lt;code&gt;password&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tend to still follow &lt;a href="https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/" rel="noopener noreferrer"&gt;BEM Notation&lt;/a&gt; for any classnames that I write. Hence, you will see that some classnames have a JavaScript namespace, and are therefore prepended with &lt;code&gt;js-&lt;/code&gt; . This is a verbose indicator that this piece of the DOM has some behaviour acting upon it, and that JavaScript binds onto it to provide that behaviour. Hence, it reduces the risk of someone editing or removing the classname mistakenly without realizing that some javascript code depends on it. &lt;/p&gt;

&lt;p&gt;Take note of the &lt;code&gt;js-&lt;/code&gt; prepended classnames as this will allow us to bind the correct masking and unmasking behaviour in the JavaScript code. &lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2:
&lt;/h1&gt;

&lt;p&gt;THE JAVASCRIPT&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;eyeIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-eye&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eyeOffIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-eye-off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwordField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibilityToggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-password-visibility-toggle&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;visibilityToggle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;togglePasswordMask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;togglePasswordMask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;togglePasswordType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;toggleEyeIcons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;togglePasswordType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&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;passwordType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;passwordField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;passwordType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleEyeIcons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;eyeOffIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;eyeIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visible&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;Let's walkthrough the code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibilityToggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-password-visibility-toggle&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;visibilityToggle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;togglePasswordMask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We first search the DOM for the classname &lt;code&gt;js-password-visibility-toggle&lt;/code&gt;. &lt;code&gt;js-password-visibility-toggle&lt;/code&gt; is the container that contains the &lt;code&gt;eye&lt;/code&gt; icons (one hidden and one not). &lt;/p&gt;

&lt;p&gt;We then use add &lt;code&gt;addEventListener&lt;/code&gt; to listen for a  &lt;code&gt;click&lt;/code&gt; on the element. When the user clicks on the element the function &lt;code&gt;togglePasswordMask&lt;/code&gt; will be called.&lt;/p&gt;

&lt;p&gt;The reason we do not add event listeners on the individual SVG &lt;code&gt;span&lt;/code&gt; is because then we'll need to add two eventListeners to the DOM (one for the &lt;code&gt;eye&lt;/code&gt; and another for the &lt;code&gt;eye-off&lt;/code&gt;) and each of the callbacks will be doing something similar. Instead, we allow the trigger on the container and use a "sort of state" variable to figure out whether we're masking or unmasking.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;togglePasswordMask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;togglePasswordType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;toggleEyeIcons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&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 first time that we load the form the password is not visible, hence we set &lt;code&gt;visible&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; initially. &lt;/p&gt;

&lt;p&gt;Each time we click on the &lt;code&gt;eye&lt;/code&gt; icon, we toggle visible to negate its current value using &lt;code&gt;visible = !visible&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When we click we want &lt;/p&gt;

&lt;p&gt;a) the password to be revealed, i.e. &lt;code&gt;togglePasswordType&lt;/code&gt;, and &lt;/p&gt;

&lt;p&gt;b) the icon we clicked on to change - i.e. &lt;code&gt;toggleEyeIcons&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwordField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;togglePasswordType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&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;passwordType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&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;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;passwordField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;passwordType&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;&lt;code&gt;togglePasswordType&lt;/code&gt; simply sets the input type to &lt;code&gt;text&lt;/code&gt; or &lt;code&gt;password&lt;/code&gt;  depending if we want to mask or unmask the password. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eyeIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-eye&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eyeOffIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-eye-off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleEyeIcons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;eyeOffIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;eyeIcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visible&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;&lt;code&gt;toggleEyeIcons&lt;/code&gt; add and remove the &lt;code&gt;hidden&lt;/code&gt; class name depending on whether the password is visible or not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fen4ls4vpepbcofv2dd3e.gif" 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%2Fen4ls4vpepbcofv2dd3e.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That wraps it up for the code, I hope that was useful and easy to follow. Feel free to drop comments or questions below. 👇🏽&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>My guide to solving problems</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Tue, 21 Jul 2020 12:24:47 +0000</pubDate>
      <link>https://dev.to/ridhwana/my-guide-to-solving-problems-13ld</link>
      <guid>https://dev.to/ridhwana/my-guide-to-solving-problems-13ld</guid>
      <description>&lt;p&gt;Recently, I gave a talk on Problem Solving where I shared some techniques that I use to solve problems at a high level as a software engineer. In this article, I’m hoping to summarise some of the aspects that I highlighted during my presentation, but feel free to watch the video below: &lt;/p&gt;

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

&lt;p&gt;We use problem solving skills on a daily basis, but luckily for us, once we solve the problem a couple of times, it usually becomes second nature to implement that solution. &lt;/p&gt;

&lt;p&gt;For example, imagine you move to a new home in a new town. When you start work again, one of the first problems that you will be presented with is to determine the route to travel to work. In order to solve this problem, you’ll probably use a tool, like Google Maps, and then perhaps you may do some research by asking the people that you know how safe the route outlined is. You may also want to amend the route in order to pass a coffee shop, and finally you’ll try it the first day and then tweak it. After you’ve found a solution to this problem, it becomes second nature to get to work,  and you no longer need to give it any thought, thus freeing your mental capacity for other problems.&lt;/p&gt;

&lt;p&gt;In the same manner that we’ve solved this problem, we can apply similar techniques to solve software engineering problems. &lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s get into the headspace..
&lt;/h3&gt;

&lt;p&gt;I’ve often found myself going around in circles because I’ve started typing out a solution without taking the time to go through a process. If I have a daunting task, I am in one of two modes; either I have just not mustered up the courage to start the task or I jump into a solution without taking the time to understand the context and problem. Hence, I started using the following process to help me problem solve. It mostly increases the initial time, but the long term payoffs have been really beneficial. &lt;/p&gt;

&lt;p&gt;The first step in the process is to set some &lt;strong&gt;focussed time&lt;/strong&gt;. During this time I make sure I understand what I want to achieve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/iJ8MungZpGmdUtkLGL/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/iJ8MungZpGmdUtkLGL/giphy.gif" alt="headspace" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Now, let’s identify the problem?
&lt;/h3&gt;

&lt;p&gt;Thereafter, I begin to &lt;strong&gt;learn more about my problem in order to understand it&lt;/strong&gt;. I’ve been in so many meetings over my career where someone is talking to a boardroom of people about a solution, but it turns out that nobody actually understood the initial problem in the first place. Therefore, they’re not really contributing towards a practical solution. &lt;br&gt;
In order to ensure that I have clarity on the problem I like to use the following techniques: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I ask questions&lt;/strong&gt;. When you’re new to a team, company or industry this can be a bit daunting, but over the years I’ve come to realise that most of the time others have similar questions to the ones I have, and they’ve led to fruitful discussions. &lt;/li&gt;
&lt;li&gt;Once I think that I’ve understood the problem, I like to &lt;strong&gt;reiterate my understanding of the problem&lt;/strong&gt; to someone more knowledgeable. I usually say something to the effect of “Ah I see what you mean, do you mind if I explain it back to you to ensure I have clarity on the problem”. The result is that it shows the other person that you have been listening attentively and trying to understand the problem. It will definitely make you feel vulnerable as it will expose the gaps in your knowledge, but once you’ve had this conversation your knowledge then becomes stronger and more solidified than ever. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualising a problem&lt;/strong&gt; can also be key. Rather than merely using words to describe, analyze and solve the problem, using images is useful. I once read somewhere that 
"Images help the brain clarify ideas, identify underlying patterns of logic, and create meaning. A good visual invites the eyes to dart around and engage the entire brain to create a visual logic and make sense of the information to which it is being exposed. The more fully the brain is engaged in the act of analyzing and creating meaning, the richer the outcome of the problem solving activities will be. "
“Taking problems to the drawing board or whiteboard” is a common term for that reason :) &lt;/li&gt;
&lt;li&gt;Finally, I spend some time &lt;strong&gt;gathering information&lt;/strong&gt;. This can often be done through talking to people who have solved something similar. They are also called ‘domain experts’. In the context of my example at the start of the article, this would be the equivalent of asking people in the neighborhood about the safety of routes. Gathering information often arms me with knowledge to see the situation more clearly, and look at the problem in a new or different way, as well as identify options that may have not occurred to me previously. I also gather information by browsing around the net for articles and insights on how people have solved similar problems before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more clarity that I have understood the problem, the easier the process becomes. Implementing a solution halfway to realise that you didn't actually fully understand the problem, or that you’re  solving for the wrong problem can often lead to economic loss or delays in release.&lt;/p&gt;

&lt;p&gt;Often, when I finally have a full understanding of the magnanimity of the problem, I tend to go blind panic mode, whereby I feel like the problem can't entirely fit in my head. I feel overwhelmed. This is when I take a deep breath and remember that everything can be broken down into bite-sized pieces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/42wQXwITfQbDGKqUP7/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/42wQXwITfQbDGKqUP7/giphy.gif" alt="identify" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shall we break it down further?
&lt;/h3&gt;

&lt;p&gt;Big problems are nothing more than a collection of little problems. The faster I can &lt;strong&gt;break those big problems down into solvable component problems&lt;/strong&gt;, the faster I can generate ideas that will resolve my issues. I take my big problem and I ask, “what is this big problem composed of ?”, “what are the smaller issues that seem to be driving the big problem”. I break them down and then continue breaking them down into smaller and smaller issues until I can find a solution to the smallest component. Breaking up the complex problems into smaller ones that are in their simplest form allows one to rationalise about them more easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/McgWV3RzDQZZNdFWRA/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/McgWV3RzDQZZNdFWRA/giphy.gif" alt="break" width="498" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s move from problem identification to problem solving.
&lt;/h3&gt;

&lt;p&gt;Now that we’ve broken down the problem, we can start planning a solution. When planning a solution,, I use visual tools, like process flow diagrams which provide good ways to determine the flow of a solution and the different paths; or in the case of application flows, a UI sketch plays a part in forming a holistic solution thereby eliminating missing steps. &lt;/p&gt;

&lt;p&gt;Once I have all the building blocks in place, I’m ready to move to the implementation stage. When working on big software problems, &lt;strong&gt;writing pseudocode&lt;/strong&gt; is a must for me. I think of pseudocode as a sketch, or a blueprint, that allows me to first focus on the essentials before diving into the specifics. &lt;/p&gt;

&lt;p&gt;One important benefit of writing pseudocode before programming is to catch potential mistakes from the get-go. It’s far cheaper to fix mistakes before the development process begins. I tend to write my pseudo code as comments in the appropriate files.&lt;/p&gt;

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

&lt;p&gt;Thereafter, we just use our programming language to implement our solution to the problem. We &lt;strong&gt;translate the pseudo code into actual code&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Finally,
&lt;/h3&gt;

&lt;p&gt;Once the solution is packaged up in code, I am usually caught up in a  whirlwind of activities on whatever the next priority is. However,  I’ve been trying to get better at &lt;strong&gt;reflecting on the problem&lt;/strong&gt; and the way that I’ve solved it. The few times that I have done this, I’ve found that I was always able to tweak or optimise my solution in some way. &lt;/p&gt;

&lt;p&gt;Reflections for me have sometimes taken the form of a blog post, a talk or even a chat with a  colleague. It's to help me to put my thoughts in perspective, to help future me when I stumble across a similar problem and also just to share my learnings. And hey, I always feel proud of myself when I reflect upon the process, it builds up my confidence for the next problem I’m about to solve.&lt;/p&gt;

&lt;p&gt;All in all the reflection process is the best part of the process to get to because it feels like the calm after the storm and it's time to bathe in the glory of your hard work. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/8acGIeFnqLA7S/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/8acGIeFnqLA7S/giphy.gif" alt="reflect" width="250" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Until next time…
&lt;/h3&gt;

&lt;p&gt;Let’s keep solving problems 😊 &lt;/p&gt;

</description>
      <category>programming</category>
      <category>problemsolving</category>
      <category>learning</category>
    </item>
    <item>
      <title>Today I learned (or maybe googled)...</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Thu, 23 Apr 2020 11:54:48 +0000</pubDate>
      <link>https://dev.to/ridhwana/today-i-learned-maybe-googled-337j</link>
      <guid>https://dev.to/ridhwana/today-i-learned-maybe-googled-337j</guid>
      <description>&lt;p&gt;I've decided to start a "Today I learned/googled..." series where I'll be writing about what I've learnt or even googled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why start it?
&lt;/h2&gt;

&lt;p&gt;Every day whilst I'm working, I google tons of things, some of which I forget and end up googling again, and some which I actually end up retaining.&lt;/p&gt;

&lt;p&gt;I search the internet for all kinds of stuff - things that are related to syntax, the quirks of a language, the magic that happens behind a framework, or sometimes even solutions on how to solve a problem within the bounds of a language.&lt;/p&gt;

&lt;p&gt;A prime and somewhat random example is every time I write a post or any markdown I have to search the syntax for a link, or do a trial and error on whether it's like this &lt;code&gt;(Name)[LinkUrl]&lt;/code&gt; or link this ✅&lt;code&gt;[Name](LinkUrl)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/NsAXBsSzxzyK8yxHwd/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/NsAXBsSzxzyK8yxHwd/giphy.gif" alt="Google It" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My computer science degree and my senior engineer title knows no bounds and they're constantly learning from the master, google. 🤫&lt;/p&gt;

&lt;p&gt;I’m also always learning from peers, and from reading their code. Recently though, I've been working on the open source project at DEV, as part of the core team, I now actually spend a huge portion of my time not only reviewing my peers PR's but also external contributors from all over the world with such varying experience and skills. These PR's are major sources of my learning on a daily basis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/u4KibgMsDLWM0/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/u4KibgMsDLWM0/giphy.gif" alt="Learn" width="480" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It makes me want to investigate deeper into things I am interested in, to share my knowledge, interact with others about the things that I’ve learned about, to exhibit how after 9 years of being a developer I still google the silliest of things 🙈, and finally it makes me just want to write some more, which I've been wanting to do for ages.&lt;/p&gt;

&lt;p&gt;I've enjoyed reading &lt;a href="https://til.hashrocket.com/"&gt;Hashrocket's TIL&lt;/a&gt; for some time now and so I thought why not share something similar on a platform I love using.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what should you expect?
&lt;/h2&gt;

&lt;p&gt;Let's start with nothing much at first, I'd love to just showcase anything random that I learn, or anything that I know but I've had to google again over and over. Some posts may be obvious, some may be silly, some may be useful, but it's supposed to be fun, so let’s see where this goes... I'd love to have discussions and for you to pop tips and tricks that you learnt in the comments too. You'll probably see some javascript, ruby, and general coding stuff.&lt;/p&gt;

&lt;p&gt;I'm bound to learn new things every week, so why not share it? 😊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/Ti7eHdZX64NkETm7Pp/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/Ti7eHdZX64NkETm7Pp/giphy.gif" alt="Share it" width="480" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>webdev</category>
      <category>coding</category>
    </item>
    <item>
      <title>Exploring the path of a new and unfamiliar codebase</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Tue, 07 Apr 2020 07:51:55 +0000</pubDate>
      <link>https://dev.to/ridhwana/exploring-the-path-of-a-new-and-unfamiliar-codebase-49nh</link>
      <guid>https://dev.to/ridhwana/exploring-the-path-of-a-new-and-unfamiliar-codebase-49nh</guid>
      <description>&lt;p&gt;About 2 months ago I changed jobs, I started working at DEV. As a senior developer, I’ve been through the process of finding my way through a new codebase a couple of times, and each time it seems to get a little easier and quicker. However, irrespective of skill level, there will always be an adjustment period, where I enjoy spending my time feeling around the codebase that I’ll be working with. Then, over time the code seems less daunting, I start making traction, I get more confident and then finally one day I feel like I’ve been working with this codebase all my life. 🛣&lt;/p&gt;

&lt;p&gt;Doing it a couple of times has made me realise that there’s been some method to my madness; &lt;strong&gt;there are some general guidelines and techniques that I follow to familiarise myself with a new codebase&lt;/strong&gt;. So this time, as I started working on the DEV codebase, I documented this method to my madness 📝 &lt;/p&gt;

&lt;p&gt;So, where do we start? &lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s explore the production application
&lt;/h2&gt;

&lt;p&gt;Before I join a new team, I usually do some basic research on their product. I tend to download and sign up for their application as part of my interview preparation. In some cases, like DEV, I’ve already been using their platform for a while and I’m familiar with it. &lt;/p&gt;

&lt;p&gt;However, before tackling a new codebase &lt;strong&gt;I still take some time to explore the parts of the interface that I don’t regularly use&lt;/strong&gt;. For example, with DEV, I familiarised myself with the different types of editors, I explored the filters, I looked through settings, I navigated to the  sponsor pages. I want to know as much as possible, and I let myself just go on a journey of exploration. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I also prefer getting a demo of the product from a team member if possible&lt;/strong&gt;. During these demos I usually find myself being alerted to parts of the system that I did not or would not stumble upon myself. Sometimes, it's the admin interface that I did not have access to as a user or perhaps a page that was tucked away and only gets used by a certain type of user.&lt;/p&gt;

&lt;p&gt;An exploration of production also helps me to realise what the local setup of my environment should look and behave like. 🔎&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/l4KibOaou932EC7Dy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l4KibOaou932EC7Dy/giphy.gif" alt="Let's explore" width="500" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Now, we can clone the code and setup your environment
&lt;/h2&gt;

&lt;p&gt;Next up, I clone the application (if I haven’t already).Thereafter, I briefly read through the documentation for setup instructions.&lt;/p&gt;

&lt;p&gt;I feel no shame in saying that &lt;strong&gt;when I get stuck on any errors (setup or otherwise), google and stack overflow are my best friends 😁&lt;/strong&gt;. If that doesn’t work, I ask questions on my team chat, everyone on the team before me has set up the project so that means someone has most likely encountered the issue before. &lt;strong&gt;Also, as I grew as a developer I learnt the balance between having to figure out the important things by myself vs asking for help&lt;/strong&gt;. A team is there to support and help each other, and it is beneficial to ask questions. Once I’ve figured out how to proceed, I always make sure to add my findings or anything that took me some time to figure out back to the documentation so that it helps the next person. &lt;/p&gt;

&lt;p&gt;Once I’m all set up, I explore even further, this time within the codebase. I read through some code, navigate the file structures, take note of the packages and code styles that are used, and even just read some tests. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/4hnQDVKVARZ6w/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/4hnQDVKVARZ6w/giphy.gif" alt="Explore the codebase" width="500" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose some bugs or simple tasks
&lt;/h2&gt;

&lt;p&gt;Exploring is not enough, doing is key. &lt;strong&gt;When we do, we end up solidifying our knowledge and we put the theories we have about the code into practice.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, unless I’m working on a green fields project, every project has bugs - literally every single one 🐞. I like to pick up some of the bugs in the project. I do this because &lt;strong&gt;I believe that fixing a part of a codebase allows me to get a much more detailed view into the system&lt;/strong&gt;. It also keeps me focussed on my end goal of getting this small piece of functionality working without the pressure of having to think about the aspects like UI and UX of a new feature. I don’t end up getting stuck in the details, because the details have already been implemented. In addition, there is very little uncertainty about the functionality because it was determined a long time ago. Removing all these other factors allows me to focus on what I need to - just the code. It also allows me to make progress and get more confident in the codebase. &lt;/p&gt;

&lt;p&gt;Keeping the above in mind, &lt;strong&gt;when choosing my first bugs, I try to stay away from complex, uncertain and not easily replicable ones that will cause me to feel overwhelmed and block on my traction.&lt;/strong&gt; In the open source world, like DEV, this is equivalent to the ‘good first issue’ tag. Once I’m past the exploration phase that’s when I like to challenge myself even further and take on the ones that hurt my brain 🤯&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/duL28c2tptZ0zAopCf/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/duL28c2tptZ0zAopCf/giphy.gif" alt="Choose bugs" width="382" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging and Solving the bug
&lt;/h2&gt;

&lt;p&gt;Finally, &lt;strong&gt;when I tackle the bug head on, there are a couple of techniques that I use&lt;/strong&gt;. These techniques are not unique to a new codebase, but they can be applied to any problem. Here are some:&lt;/p&gt;

&lt;p&gt;First, I break up the problem into more manageable components, until they are small, less complex pieces. I then work through each piece as a task.&lt;/p&gt;

&lt;p&gt;When debugging, I trace through the code in question from start to end (i.e. across the backend to the frontend) in order to find the point where the issue lies. I do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I use &lt;strong&gt;loads of logs&lt;/strong&gt;! There's been times when I've added logs to every single function in a file to figure out it's path. Once I know the path then I’m easily able to figure out what may be going wrong. During this time, I’m learning about how the code works. The two things that I do diligently is I name my logs appropriately so as to not get lost in them and I also keep a note of the order of the logs (especially in javascript where things get performed asynchronously).&lt;/li&gt;
&lt;li&gt;When I’m stuck, I sometimes &lt;strong&gt;comment out pieces of code&lt;/strong&gt;, just to see what the repercussions are and how or if the system explodes 💥. Commenting out code usually indicates to me whether I’m looking in the right place. If I comment out code and the interface or feature still continues working, it means I’m clearly working in the wrong area of the codebase. I always keep in mind that I should not be afraid to try anything, it’s usually not  possible to break an application in the development environment (at least I really hope so, or else we have bigger problems!!), and everything should be reversible. P.S, make sure that when you changing code on your development environment, you’re not mistakenly refreshing production wondering why your change is not working 🤦🏽‍♀️ Yes, this has happened to me numerous times!&lt;/li&gt;
&lt;li&gt;I use &lt;strong&gt;debuggers to stop the execution of the code&lt;/strong&gt; in order to play with portions of the code that don’t make sense to me. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/hrSFdM4rg8VFpXyz2m/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/hrSFdM4rg8VFpXyz2m/giphy.gif" alt="Debugging" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That sounds cool, but, what if I’m still stuck?
&lt;/h2&gt;

&lt;p&gt;If after debugging I find that I’m still stuck, I do some more research, try writing down the problem and maybe even rubber ducking, but at some point if all that doesn’t work then asking for a second pair of eyes 👀on the problem becomes key. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When we’re asking for help, it's important that we give colleagues as much information about the problem&lt;/strong&gt;. I usually start off by describing the problem to them, then explaining what I tried to do to solve it and what were the findings of it, and finally I ask direct questions on the portion of the code that isn’t making sense or that I need assistance with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Showing the work in progress also helps to give the other person perspective, as well as helps them to visually see what you’ve been working on to be able to assist.&lt;/strong&gt; It reduces the time wasted for them to have to try that which you’ve tried already. It is for this reason that &lt;a href="https://github.blog/2019-02-14-introducing-draft-pull-requests/"&gt;draft PR’s&lt;/a&gt; have become really useful. Besides, it's better to get feedback earlier rather than later. Finally, if asynchronous feedback is not helping, don’t feel shy to ask someone in the team who's more knowledgeable on the topic to pair program just to get over the bump. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/nE5FitGTYa5Xi/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/nE5FitGTYa5Xi/giphy.gif" alt="Pair Programming" width="384" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  During this process, what should I be mindful of?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I believe that &lt;strong&gt;changes should be made incrementally instead of in one ginormous pull request&lt;/strong&gt;. Testing often is essential too. &lt;/li&gt;
&lt;li&gt;Being conscious of the changes we make and adhering to the coding style ensures that we &lt;strong&gt;have a consistent codebase&lt;/strong&gt;. It's important to feel confident to make improvements in the application, but when introducing new tools or technology that will affect other teams or the direction of the project we need to be sure to consult or give a heads up to everyone else (depending on the flexibility of the company).&lt;/li&gt;
&lt;li&gt;Irrespective of our skill level, we need to remember to &lt;strong&gt;be empathetic and kind to the person who wrote the code before us&lt;/strong&gt;. Often I hear developers refer to the crap code that they inherited from the previous developer, but we need to keep in mind that we do not know the full context of the situation under which the code was written. &lt;/li&gt;
&lt;li&gt;Sometimes we’ll end up breaking things - &lt;strong&gt;shit happens, acknowledge it, learn from it and move on!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/WrTWAjKnfuU9v9URwA/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/WrTWAjKnfuU9v9URwA/giphy.gif" alt="Together" width="480" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In conclusion, when one is not armed with techniques to approach a codebase, it can feel overwhelming and intimidating. However, as soon as there is a method to the madness it can easily metamorph those feelings to excitement and enjoyment instead. I hope that this does that for you :)!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>codenewbie</category>
      <category>tips</category>
    </item>
    <item>
      <title>Nevertheless, Ridhwana Coded</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Mon, 09 Mar 2020 08:15:38 +0000</pubDate>
      <link>https://dev.to/ridhwana/nevertheless-ridhwana-coded-1pe5</link>
      <guid>https://dev.to/ridhwana/nevertheless-ridhwana-coded-1pe5</guid>
      <description>&lt;p&gt;As I was growing up, when I was asked what I wanted to become, it started off as a 👸🏽princess, then a 🚗car racer, a 👩🏽‍🏫teacher, an 🧾accountant, but never did I once say any type of engineer.&lt;/p&gt;

&lt;p&gt;You see the thing is, I’d never really seen any girls operate computers or build bridges. I knew what the world taught me - pink is for girls, we play with princesses, and maybe half day jobs with holidays are best. &lt;/p&gt;

&lt;p&gt;I didn’t learn to program from an early age and I didn’t know anyone that did, in fact to be honest I didn’t know what programming entailed.&lt;/p&gt;

&lt;p&gt;Almost a decade later... and I'm a &lt;a href="https://dev.to/"&gt;software engineer at DEV&lt;/a&gt;, a company whose mission I believe in, I &lt;a href="https://ridhwana.com/speaking/"&gt;speak at conferences&lt;/a&gt; about the things that I love, and I &lt;a href="http://kasimaths.org/"&gt;run a non profit organisation&lt;/a&gt; to help others. I'm not a princess, but I am someone that has mapped out her own journey and worked really hard to get there, so maybe I could be my own superhero?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/9FZp3wje5JyjkNTszy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/9FZp3wje5JyjkNTszy/giphy.gif" alt="superhero"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nevertheless, how did I get from wanting to be a princess to becoming a software engineer?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Firstly, I have parents who didn't limit me. They let me choose the career path that I wanted to even though I really had no clue what Computer Science was, but they let me explore and knew I would find my path.&lt;/li&gt;
&lt;li&gt;I worked really really hard. It wasn't always easy. Coming from a non-coding background, I felt like I lagged behind with understanding certain coding concepts at university, because it was assumed that I had done coding at school. Whilst I was learning what an if statement was, the curriculum dictated that we built web sockets already.&lt;/li&gt;
&lt;li&gt;Once I was in the industry I didn't let being the only women in the room stop me. Yes, it was difficult, and I had to prove myself over and over, but I did it until I no longer needed to. &lt;/li&gt;
&lt;li&gt;I learned and forced myself out of my comfort zone - the bigger the challenge, the more I wanted to achieve it. &lt;/li&gt;
&lt;li&gt;And finally, I let myself be inspired by others in the industry. I took on mentors when I felt that I needed guidance, and I asked for help when I was lost. I contributed where I could.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are still challenges that I'm overcoming on a daily basis but I finally believe that we can overcome them together as an industry. Each day in the smallest of actions, I strive for a world where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;everyone gets paid equally, based on their skills and NOT their gender.&lt;/li&gt;
&lt;li&gt;a women in the boardroom no longer has to prove herself, in order to get her voice heard.&lt;/li&gt;
&lt;li&gt;tech conferences are filled with diversity and the excuse is no longer, 'but we couldn't find a women'.&lt;/li&gt;
&lt;li&gt;the working environment is tailored to suit the needs of both men and women.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe that over the last decade we have made progress, but we still have a long way to go. It is with constant awareness and small changes that lead to bigger ones that we can get there.. together. On that note, Happy International Women's Day!💜&lt;/p&gt;

</description>
      <category>wecoded</category>
    </item>
    <item>
      <title>Performance Budgets, do you use them?</title>
      <dc:creator>Ridhwana Khan</dc:creator>
      <pubDate>Tue, 03 Mar 2020 10:20:11 +0000</pubDate>
      <link>https://dev.to/ridhwana/performance-budgets-do-you-use-them-23cn</link>
      <guid>https://dev.to/ridhwana/performance-budgets-do-you-use-them-23cn</guid>
      <description>&lt;p&gt;I've been doing loads of more research on Performance for the past couple of weeks and &lt;a href="https://addyosmani.com/blog/performance-budgets/"&gt;Performance Budgets&lt;/a&gt; have caught my eye. Curious to know how many teams use performance budgets and how you've implemented them? Also, what kind of improved ripple effects has this caused?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
