<?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: Katherine Kelly</title>
    <description>The latest articles on DEV Community by Katherine Kelly (@katkelly).</description>
    <link>https://dev.to/katkelly</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%2F238944%2F0a1f65a4-756c-4830-8fb3-d32f878ca6b8.JPG</url>
      <title>DEV Community: Katherine Kelly</title>
      <link>https://dev.to/katkelly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/katkelly"/>
    <language>en</language>
    <item>
      <title>Technical Interview Resources for the Junior Dev</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Thu, 20 Aug 2020 20:07:52 +0000</pubDate>
      <link>https://dev.to/katkelly/technical-interview-resources-for-the-junior-dev-2i3m</link>
      <guid>https://dev.to/katkelly/technical-interview-resources-for-the-junior-dev-2i3m</guid>
      <description>&lt;p&gt;During my job search post coding bootcamp, I’ve had several interviews covering a wide range of technical concepts and behavioral scenarios. Even as a junior software engineer, it’s clear to me that software engineers need a strong foundation in computer science fundamentals like data structures and algorithms, as they serve as the bedrock of technical interviews. &lt;/p&gt;

&lt;p&gt;I naively thought technical interviews would &lt;em&gt;always&lt;/em&gt; be centered around solving a Leetcode-style problem that companies use to assess your coding ability for efficiency, readability, and completeness. Yes, you will frequently encounter this type of interview, however, technical interview questions can run the gamut beyond a programming challenge. The best way to prepare for an interview is to feel prepared for whatever may be thrown at you. Of course, this is easier said than done, but every interview will only better prepare you for the next one.&lt;/p&gt;

&lt;p&gt;Yet, it can feel like information overload on the internet with free and paid resources alike that purport to get you learning everything you need to know before your upcoming interview. Though I can’t speak about what is considered the norm in technical interviewing, I can only provide my own following observations and resources I found helpful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Phone Screen
&lt;/h3&gt;

&lt;p&gt;Technical phone interview rounds have been more vague on what to expect, other than being told that I'll have to solve a technical coding question. As an example, I got this once from a recruiter, “(the coding question) will be in the areas of design, algorithm and/or data structure”, and the interviewer gave me a medium-level Leetcode problem to solve. Another time, a recruiter said I can anticipate “questions regarding computer science and operating system fundamentals” and I was asked to flex my object-oriented design skills with an open-ended problem on designing a library-like service. &lt;/p&gt;

&lt;h3&gt;
  
  
  Interview With Hiring Manager
&lt;/h3&gt;

&lt;p&gt;In another interview scenario when speaking with a hiring manager, it’s been my experience that there is a 50/50 chance you will be asked technical trivia questions (again, just my experience so take this percentage with a grain of salt). For an associate frontend role at a large tech company, I was peppered with JavaScript questions after several behavioral questions from the engineering manager. For a full stack role, I was asked questions about Unix, Git, and SQL, with the head of engineering acknowledging that several of the questions were “esoteric”, especially for a junior developer like me who hasn't had any work experience yet. &lt;/p&gt;

&lt;h3&gt;
  
  
  Final Round Interview
&lt;/h3&gt;

&lt;p&gt;In final round interviews, the recruiter or hiring manager was generally explicit on what I should expect for each interview session during the long day, even prepping me with sample questions. Perhaps this is due to the fact you’ve made it as far as you have (congratulations!) and they want to see you succeed. &lt;/p&gt;

&lt;p&gt;Below, I’ve compiled resources I’ve found helpful when preparing for various types of technical interviews and resources found after the interview when I wanted to brush up more on the topic. Feel free to share any resources you’ve found helpful below in the comments! &lt;/p&gt;

&lt;p&gt;**&lt;em&gt;resource I recommend&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Data Structures and Algorithms / Coding Challenges
&lt;/h2&gt;

&lt;p&gt;** &lt;a href="https://leetcode.com/"&gt;Leetcode&lt;/a&gt;&lt;br&gt;
** &lt;a href="https://www.interviewcake.com/"&gt;Interview Cake&lt;/a&gt; (&lt;em&gt;paid resource for full course&lt;/em&gt;)&lt;br&gt;
** &lt;a href="http://www.crackingthecodinginterview.com/"&gt;Cracking the Coding Interview&lt;/a&gt; (&lt;em&gt;book for purchase&lt;/em&gt;)&lt;br&gt;
&lt;a href="http://www.crackingthecodinginterview.com/uploads/6/5/2/8/6528028/cracking_the_coding_skills_-_v6.pdf"&gt;Cracking the Coding Skills PDF&lt;/a&gt; &lt;br&gt;
&lt;a href="https://app.codility.com/programmers/lessons/1-iterations/"&gt;Codility&lt;/a&gt;&lt;br&gt;
&lt;a href="https://blog.hackerrank.com/introducing-cracking-the-coding-interview-tutorial-new-study-on-interview-practice/"&gt;HackerRank - Introducing Cracking the Coding Interview Tutorial and Practice&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  System Design / Systems Architecture
&lt;/h2&gt;

&lt;p&gt;** &lt;a href="https://www.educative.io/courses/grokking-the-system-design-interview"&gt;Grokking the System Design Interview&lt;/a&gt; (&lt;em&gt;paid course&lt;/em&gt;)&lt;br&gt;
&lt;a href="https://gist.github.com/vasanthk/485d1c25737e8e72759f"&gt;System Design Cheatsheet&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hackernoon.com/top-10-system-design-interview-questions-for-software-engineers-8561290f0444"&gt;Top 10 System Design Interview Questions for Software Engineers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://blog.pramp.com/how-to-succeed-in-a-system-design-interview-27b35de0df26"&gt;How to Succeed in a System Design Interview&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Knowledge and Judgement
&lt;/h2&gt;

&lt;p&gt;** &lt;a href="https://www.reddit.com/r/cscareerquestions/comments/6wusbe/what_are_some_essential_technical_but_noncoding/"&gt;Reddit - What Are Some Essential Technical (But Non-Coding) Interview Questions That New Grads Should Know the Answer To?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery#:~:text=Cross%2Dsite%20request%20forgery%2C%20also,that%20the%20web%20application%20trusts."&gt;Cross-Site Request Forgery&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rubygarage.org/blog/single-page-app-vs-multi-page-app"&gt;What’s the Difference Between Single-Page and Multi-Page Apps?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/a-lady-dev/single-page-applications-a-powerful-design-pattern-for-modern-web-apps-ec3590bb7e7a"&gt;Single Page Applications: A Powerful Design Pattern for Modern Web Apps&lt;/a&gt;&lt;br&gt;
** &lt;a href="https://www.w3.org/WAI/standards-guidelines/"&gt;W3C Accessibility Standards Overview&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby on Rails
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/dcuadraq/f63476b3048c5b76318abd28831a00d6"&gt;Rails Antipatterns&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.ombulabs.com/blog/code-refactor/refactoring-with-design-patterns.html"&gt;Refactoring: Clean Your Ruby Code With Design Patterns&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://medium.com/javascript-scene/10-interview-questions-every-javascript-developer-should-know-6fa6bdf5ad95"&gt;10 Interview Questions Every JavaScript Developer Should Know&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.cloudflare.com/learning/performance/why-minify-javascript-code/"&gt;Why Minify JavaScript Code?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop"&gt;Concurrency Model and the Event Loop&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  React
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://css-tricks.com/server-side-react-rendering/"&gt;Server Side React Rendering&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/27290354/reactjs-server-side-rendering-vs-client-side-rendering"&gt;ReactJS Server-Side Rendering VS Client-Side Rendering&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Systems
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/List_of_Unix_commands"&gt;List of Unix Commands&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things to Know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How systems boot and load Linux &lt;/li&gt;
&lt;li&gt;The shell, and how it interacts with the underlying operating system &lt;/li&gt;
&lt;li&gt;UNIX file systems and storage &lt;/li&gt;
&lt;li&gt;Process management and state &lt;/li&gt;
&lt;li&gt;The Linux virtual memory model &lt;/li&gt;
&lt;li&gt;Techniques for resource control &lt;/li&gt;
&lt;li&gt;Common system troubleshooting tools and techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Object Oriented Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.quora.com/How-to-approach-object-oriented-design-questions-in-programming-interviews"&gt;How to Approach Object Oriented Design Questions in Programming Interviews?&lt;/a&gt;&lt;br&gt;
** &lt;a href="https://hackernoon.com/the-top-10-object-oriented-design-interview-questions-developers-should-know-c7fc2e13ce39"&gt;The Top 10 Object-Oriented Design Questions Developers Should Know&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Thinking
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/ketans-blog/product-managers-interviewing-engineers-511c5b4571a9"&gt;Product Managers Interviewing Engineers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.atlassian.com/agile/product-management/product-manager"&gt;Product Manager&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/joshnh/Git-Commands"&gt;Git Commands&lt;/a&gt;&lt;br&gt;
&lt;a href="https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/"&gt;Git Tips and Tricks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Behavioral
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;not technical per se, but you will often get asked these questions during your technical interview, usually about collaboration and challenges, etc.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.crackingthecodinginterview.com/uploads/6/5/2/8/6528028/cracking_the_soft_skills_-_v6.pdf"&gt;Cracking the Soft Skills PDF&lt;/a&gt;&lt;br&gt;
** &lt;a href="https://hired.com/blog/candidates/30-behavioral-interview-questions-should-be-ready-to-answer/"&gt;30 Behavioral Interview Questions You Should Be Ready to Answer&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Binary Search and How to Implement It</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Fri, 14 Aug 2020 21:23:43 +0000</pubDate>
      <link>https://dev.to/katkelly/binary-search-and-how-to-implement-it-15e6</link>
      <guid>https://dev.to/katkelly/binary-search-and-how-to-implement-it-15e6</guid>
      <description>&lt;p&gt;Binary search is an efficient way to search through a sorted array for a target value. It takes a divide and conquer approach, where we get the middle element of the array and create left and right side arrays without the middle element (divide). Then we’ll check to see if the target is less than or greater than the middle element, and if so, we’ll keep searching through the left half or right half, respectively, with each step effectively halving the number of elements to be looked at (conquer). &lt;/p&gt;

&lt;h3&gt;
  
  
  Time and Space Complexity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The time complexity of binary search is logarithmic at O(log n)&lt;/strong&gt;. We will look through only half of an increasingly smaller data set per step. To get a time complexity of less than O(n), we must avoid touching all &lt;em&gt;n&lt;/em&gt; elements, which binary search accomplishes. &lt;/p&gt;

&lt;p&gt;Space complexity will depend on how you implement your algorithm (recursively vs. iteratively and create new subarrays vs. searching in-place). Implementing a recursive algorithm can have a space complexity of O(n) or O(log n), depending on if new subarrays are created. Taking an iterative approach will result in O(1) space. &lt;/p&gt;

&lt;h3&gt;
  
  
  Recursive Approach | new subarrays, O(n) space
&lt;/h3&gt;

&lt;p&gt;When I learned binary search, I got familiar with this approach first of creating new arrays as it was easy to remember and intuitive. However, the tradeoff for ease of simple implementation is additional space, which is a factor you’ll want to consider in any situation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// set your base case for recursive functions&lt;/span&gt;
  &lt;span class="c1"&gt;// if the array is empty, we know the element is not present  &lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;return&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;let&lt;/span&gt; &lt;span class="nx"&gt;midIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;midIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="c1"&gt;// subarrays should not include the middle element&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;leftArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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;midIdx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rightArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;midIdx&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="c1"&gt;// if target is less than midVal, target should be likely in&lt;/span&gt;
  &lt;span class="c1"&gt;// the left array (pass in leftArray to the recursive call)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// if target is greater than midVal, target should be likely &lt;/span&gt;
  &lt;span class="c1"&gt;// in the right array (pass in rightArray to the recursive call)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rightArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Recursive Approach | in-place, O(log n) space
&lt;/h3&gt;

&lt;p&gt;To be able to reference the original array’s indices and keep track of the pointers that will help form the left and right halves of the array, we’ll want to pass in additional arguments to the function called &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt;. &lt;code&gt;low&lt;/code&gt;’s default value should be set to 0, as it serves as the lowest index while &lt;code&gt;high&lt;/code&gt;’s default value is the last index in the array. &lt;code&gt;midIdx&lt;/code&gt; is the middle index that will be the “halving point” of the “subarrays”, and we'll compare the element at its index (&lt;code&gt;midVal&lt;/code&gt;) to the target value to see if the values match, or if the target is greater or less than the middle value.&lt;/p&gt;

&lt;p&gt;This method will cut the space complexity down to O(log n), which is due to its call stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;low&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="nx"&gt;high&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// set your base case for recursive functions&lt;/span&gt;
  &lt;span class="c1"&gt;// if low is greater than high, that means we’ve gone through &lt;/span&gt;
  &lt;span class="c1"&gt;// the array and target is not present&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// add low + high and divide in half to get midIdx &lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;midIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;midIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// when passing in low and high arguments to the recursive call, &lt;/span&gt;
  &lt;span class="c1"&gt;// be sure to exclude midIdx (b/c we've already looked at it)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;midIdx&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;midIdx&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="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Iterative Approach | in-place, O(1) space
&lt;/h3&gt;

&lt;p&gt;The iterative approach also requires keeping track of &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; variables that act as the left and right sides of the array, with &lt;code&gt;midIdx&lt;/code&gt; acting as the halving point and where we’ll be checking to see if &lt;code&gt;midVal&lt;/code&gt; is  equal to, less than, or greater than the target.&lt;/p&gt;

&lt;p&gt;Though a recursive function may be easier to implement, an iterative approach will result in a space complexity of O(1).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;binarySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// setting the low and high indices&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;low&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="c1"&gt;// want to keep searching until at least one element &lt;/span&gt;
  &lt;span class="c1"&gt;// exists in the array&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;high&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;midIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&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;midVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;midIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// return true if target equals midVal&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// if target is less than midVal, reassign high to &lt;/span&gt;
      &lt;span class="c1"&gt;// midIdx - 1 (bc we've already looked at midIdx)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;midVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;midIdx&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="c1"&gt;// else, the target is in the second half of array so &lt;/span&gt;
      &lt;span class="c1"&gt;// reassign low to midIdx + 1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;midIdx&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;Check out the resources below for more information on binary search. Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.interviewcake.com/concept/java/binary-search"&gt;Binary Search Algorithm - Interview Cake&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm#:~:text=In%20computer%20science%2C%20binary%20search,middle%20element%20of%20the%20array."&gt;Binary Search Algorithm - Wikipedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://iq.opengenus.org/binary-search-iterative-recursive/#:~:text=The%20major%20difference%20between%20the,the%20iterative%20version%20is%20efficient."&gt;Iterative and Recursive Binary Search Algorithm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Destination Memoization</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Thu, 06 Aug 2020 07:00:52 +0000</pubDate>
      <link>https://dev.to/katkelly/destination-memoization-1k62</link>
      <guid>https://dev.to/katkelly/destination-memoization-1k62</guid>
      <description>&lt;p&gt;If you read my post last week about &lt;a href="https://dev.to/katkelly/destination-tabulation-18hj"&gt;tabulation&lt;/a&gt;, one of two dynamic programming (DP) strategies used to break down a problem into similar and smaller subproblems, then you know this post is a follow up about its sister strategy: memoization. Also, the post title is another giveaway about the wonders of memoization. Alas, the destination of this post is not a tropical vacation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Memoization is a recursive DP strategy that utilizes a hash map to store the results of the subproblems&lt;/strong&gt; ((since this will be written in JavaScript, I’ll refer to this as an object going forward). The object is typically referred to as the memo (hence the moniker memoization!) and acts as a cache, and any subsequent calls to it will simply fetch the stored result in constant time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Leetcode: Fibonacci
&lt;/h2&gt;

&lt;p&gt;To illustrate memoization, I’ll walk through the following Leetcode problem and classic code challenge: &lt;a href="https://leetcode.com/problems/fibonacci-number/submissions/"&gt;Fibonacci&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Fibonacci numbers, commonly denoted F(n) form a sequence,
called the Fibonacci sequence, such that each number is the sum of
the two preceding ones, starting from 0 and 1. That is,
F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), for N &amp;gt; 1.
Given N, calculate F(N).

Example 1:
Input: 2
Output: 1
Explanation: F(2) = F(1) + F(0) = 1 + 0 = 1

Example 2: 
Input: 5
Output: 
Explanation: F(5) = F(4) + F(3) = 3 + 2 = 5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Set Up Your Memo
&lt;/h3&gt;

&lt;p&gt;As we’ll build a recursive function, we will want to pass in a memo object as an additional argument to the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&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 keys in the object will represent unique arguments passed to the function, and the values will represent the result for those arguments. In this specific problem, the keys will be numbers going up to and including &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a Base Case Condition
&lt;/h3&gt;

&lt;p&gt;All recursive functions need a base case that will ultimately halt the recursion and exit the function (otherwise we would enter into an infinite loop) and a recursive step where we continue the recursion by making another call. &lt;/p&gt;

&lt;p&gt;The base case condition will return the stored value in the object if the function’s argument is in the memo (exists as a key).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is also a good time to take care of edge cases if &lt;code&gt;n === 0&lt;/code&gt; or &lt;code&gt;n === 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Recursive Call and Storing the Results
&lt;/h3&gt;

&lt;p&gt;Before we return the result of the recursive call, we’ll want to store it in the memo. The efficiency of memoization is with the lookup of the previous subproblem’s result, instead of having to recompute the same problem again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Time and Space Complexity
&lt;/h3&gt;

&lt;p&gt;The above method uses O(n) time and space.&lt;/p&gt;

&lt;p&gt;I hope you found this helpful. If you want to learn more about memoization, do check out the materials below. Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.interviewcake.com/concept/javascript/memoization"&gt;Memoization - Interview Cake&lt;/a&gt;&lt;br&gt;
&lt;a href="https://leetcode.com/problems/fibonacci-number/"&gt;Fibonacci - Leetcode&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Destination Tabulation</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Sat, 01 Aug 2020 06:59:45 +0000</pubDate>
      <link>https://dev.to/katkelly/destination-tabulation-18hj</link>
      <guid>https://dev.to/katkelly/destination-tabulation-18hj</guid>
      <description>&lt;p&gt;Welcome to my post on tabulation, where the destination is learning about tabulation (sorry, no tropical vacation)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabulation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tabulation is an iterative dynamic programming strategy used to efficiently solve large problems by breaking down the problem into smaller problems.&lt;/strong&gt; It’s considered a &lt;em&gt;bottom up approach&lt;/em&gt; since it solves all of the related subproblems first before building larger values from these and solving the the big problem last.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The results of each solved subproblem is stored in a table of &lt;em&gt;n&lt;/em&gt; elements&lt;/strong&gt; (hence its moniker tabulation, but it’s just a plain old array), with the first element in the table being the smallest subproblem and the last element representing the largest and final answer. &lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Dynamic Programming?
&lt;/h3&gt;

&lt;p&gt;Dynamic programming (DP) is an algorithmic technique used to efficiently solve an optimization problem by breaking the problem down into smaller subproblems. &lt;strong&gt;Efficiency is achieved by avoiding duplication calculations and only solving each subproblem once by storing its result in an additional data structure.&lt;/strong&gt; Each subsequent subproblem will build on the previous subproblem’s result until you get to the last and final problem. There are two DP strategies: tabulation and memoization.&lt;/p&gt;

&lt;p&gt;Keep in mind that utilizing DP does not apply for every problem. &lt;strong&gt;It can only be used if the problem has a sense of repetitive subproblems that overlap.&lt;/strong&gt; It can be tricky at first to spot whether a problem should be solved using DP, but more practice and exposure to problems will get you there.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Leetcode: Climbing Stairs
&lt;/h2&gt;

&lt;p&gt;To illustrate tabulation, I’ll walk through the following Leetcode problem: &lt;a href="https://leetcode.com/problems/climbing-stairs/"&gt;Climbing Stairs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are climbing a stair case. It takes n steps to reach the top.
Each time you can either climb 1 or 2 steps. In how many distinct
ways can you climb to the top?

Example 1:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps

Example 2:
Input: 4
Output: 5
Explanation: There are 5 ways to climb to the top.
1. 1 step + 1 step + 1 step + 1 step
2. 2 steps + 1 step + 1 step
3. 2 steps + 2 steps
4. 1 step + 1 step + 2 steps
5. 1 step + 2 step + 1 step
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In thinking about our problem, we know it will be &lt;em&gt;n&lt;/em&gt; steps to the top but we need to figure out the distinct ways to reach the top. You can only take 1 step or 2 steps each time. &lt;/p&gt;

&lt;p&gt;Reaching the &lt;i&gt;i&lt;sup&gt;th&lt;/sup&gt;&lt;/i&gt; step can be done in one of two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Take a single step from (&lt;i&gt;i&lt;/i&gt; - 1)&lt;sup&gt;th&lt;/sup&gt; step&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Take a step of two from (&lt;i&gt;i&lt;/i&gt; - 2)&lt;sup&gt;th&lt;/sup&gt; step&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The total number of ways to reach &lt;i&gt;i&lt;sup&gt;th&lt;/sup&gt;&lt;/i&gt; is equal to the sum of the ways of reaching (&lt;i&gt;i&lt;/i&gt; - 1)&lt;sup&gt;th&lt;/sup&gt; step and ways of reaching (&lt;i&gt;i&lt;/i&gt; - 2)&lt;sup&gt;th&lt;/sup&gt; step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up Your Table
&lt;/h3&gt;

&lt;p&gt;The first thing you'll want to do is set up your table array based on the size of your input. We can do this two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create the array off the bat with &lt;code&gt;n&lt;/code&gt; elements and filling all values with 0 (since we know we'll be dealing with integers). Then we'll want to initialize some values in the table that will answer trivially small subproblems and edge cases (usually the first entry in the problem).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&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;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;fill&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="c1"&gt;// [0, 0, 0, 0]&lt;/span&gt;
&lt;span class="nx"&gt;table&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="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="nx"&gt;table&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// with 2 steps, there are 2 ways to climb to the top&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;declare the array with the smallest subproblems already included. I'll go with this method since arrays are dynamic in JavaScript and it'll be a bit less code.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&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="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="c1"&gt;// initialized it to include `n = 2`'s subproblem result or else&lt;/span&gt;
&lt;span class="c1"&gt;// it would throw off the below implementation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The following represents what our initialized table looks like: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;0&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;table[i]&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Iterate Through N to Fill in Remaining Table Values
&lt;/h3&gt;

&lt;p&gt;We'll then want to iterate using a &lt;code&gt;for&lt;/code&gt; loop starting at 3 since we've already pre-populated the array to account for the earlier subproblems. We'll want to terminate the loop when &lt;code&gt;i&lt;/code&gt; is less than or equal to &lt;code&gt;n&lt;/code&gt; (&lt;code&gt;i &amp;lt;= n&lt;/code&gt;) since the indexes of the array line up with &lt;code&gt;n&lt;/code&gt;, as we took 0 steps into consideration.&lt;/p&gt;

&lt;p&gt;In the loop, we'll populate the rest of our table by setting the value at index &lt;code&gt;i&lt;/code&gt; to be the sum of the previous two subproblems at index &lt;code&gt;i - 1&lt;/code&gt; and &lt;code&gt;i - 2&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Finally, we can return &lt;code&gt;table[n]&lt;/code&gt; since it will be the largest final answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;climbingStairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;table&lt;/span&gt; &lt;span class="o"&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="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="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;climbingStairs&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="c1"&gt;// 5&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;climbingStairs&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="c1"&gt;// 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Visual representation of getting &lt;em&gt;4&lt;/em&gt;: &lt;br&gt;
table[4 - 1] + table[4 - 2] &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;0&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;&lt;em&gt;2&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;3&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;table[i]&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;em&gt;2&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;3&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Time and Space Complexity
&lt;/h3&gt;

&lt;p&gt;The above method uses O(n) time since it has a loop that runs n - 3 times. &lt;/p&gt;

&lt;p&gt;The space complexity above is also O(n) because it stores a full array of the subproblems. &lt;/p&gt;

&lt;p&gt;There is a way to optimize on space down to O(1) by not storing the full array. We'll only need to save the last two subproblems to help calculate the next one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;climbingStairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// handling edge cases if n equals 0 or 1&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// create last and secondLast variables with 2 and 1, respectively&lt;/span&gt;
  &lt;span class="c1"&gt;// to handle edge cases&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;secondLast&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="c1"&gt;// &lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// initialize temp variable to store last's current value as&lt;/span&gt;
   &lt;span class="c1"&gt;// we'll be reassigning last to the the sum of last + secondLast&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;secondLast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;secondLast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;climbingStairs&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="c1"&gt;// 8&lt;/span&gt;

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



&lt;p&gt;I hope you found this helpful. Next week, I’ll look at memoization, the other dynamic programming strategy that utilizes recursion and a hash map. Until then, happy coding! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/climbing-stairs/"&gt;Climbing Stairs - Leetcode&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/courses/grokking-dynamic-programming-patterns-for-coding-interviews/m2G1pAq0OO0#:~:text=Dynamic%20Programming%20(DP)%20is%20an,optimal%20solution%20to%20its%20subproblems."&gt;What is Dynamic Programming? - Educative.io&lt;/a&gt;&lt;br&gt;
&lt;a href="https://open.appacademy.io/learn/full-stack-online/data-structures-and-algorithms/tabulation-notes"&gt;Tabulation - App Academy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;Dynamic Programming - Wikipedia&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Trie Like Pie</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Fri, 24 Jul 2020 07:45:09 +0000</pubDate>
      <link>https://dev.to/katkelly/trie-like-pie-539o</link>
      <guid>https://dev.to/katkelly/trie-like-pie-539o</guid>
      <description>&lt;p&gt;If you're not familiar with tries and want to learn more, then this post is for you! A trie is like pie in that both rhyme* but that’s where the similarities end.  &lt;strong&gt;A trie is a tree-like data structure used to efficiently store a set of strings. It’s also commonly referred to as a prefix tree or digital tree.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;and it’s a helpful mnemonic since I initially pronounced trie like ‘tree’. Fun fact- trie was coined by Edward Fredkin who pronounced it like 'tree' as in 're-trie-val', but others have since pronounced it as 'try' to distinguish it from 'tree'&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Trie Works
&lt;/h2&gt;

&lt;p&gt;A trie is known as a prefix tree because it builds a path from the root of the tree to any node that represents a prefix for at least one string in the set. &lt;/p&gt;

&lt;p&gt;The root is associated with an empty string, and all of the descendants of a node will have a common prefix of the string associated with that node. The final leaf in the path acts as a terminal node and results in a complete word &lt;strong&gt;(a word recognized by the trie must begin at the root and end at a terminal node).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below is a trie visualized with the darker shade representing a terminal node/completed word.&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%2Fraw.githubusercontent.com%2Fkat-star%2Fblog-images%2Fmaster%2Ftrie-example.001.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fkat-star%2Fblog-images%2Fmaster%2Ftrie-example.001.jpeg" alt="trie example in pink"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use a Trie
&lt;/h2&gt;

&lt;p&gt;It’s useful to use a trie if you have a dictionary of words and you want an efficient insert and lookup to see if a word exists in the dictionary (i.e. a spellcheck or predictive text program). &lt;/p&gt;

&lt;h2&gt;
  
  
  Big O Time and Space Complexity
&lt;/h2&gt;

&lt;p&gt;The worst case time complexity for both inserting and searching is O(m) where &lt;em&gt;m&lt;/em&gt; is the length of the word. Complexity depends on how long the given word is and not the number of words stored in the trie, as we will only be traveling a single path from root to terminal node.&lt;/p&gt;

&lt;p&gt;The space complexity for a trie will depend on how often prefixes are shared among words. The guaranteed worst case is O(m * n) where &lt;em&gt;m&lt;/em&gt; is the length of the word and &lt;em&gt;n&lt;/em&gt; is the number of words.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a Trie
&lt;/h2&gt;

&lt;p&gt;We can implement a trie by creating both a Trie and Node class. &lt;/p&gt;

&lt;h3&gt;
  
  
  Node Class
&lt;/h3&gt;

&lt;p&gt;The Node class will not store values within the nodes of a trie, which is different than other tree structures. Instead, &lt;strong&gt;we will store values for each edge that leaves a node.&lt;/strong&gt; Since a trie is not a binary tree, it can have any number of children, which will be stored in an &lt;code&gt;Object&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;isTerminal&lt;/code&gt; property will keep track of whether the node represents a terminal node. Remember, a word is only recognized by the trie if it begins at the root and ends at a terminal node (last leaf in the path).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isTerminal&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Trie Class
&lt;/h3&gt;

&lt;p&gt;For a basic Trie class implementation, we'll include &lt;code&gt;insert()&lt;/code&gt; and &lt;code&gt;search()&lt;/code&gt; functions. &lt;/p&gt;
&lt;h3&gt;
  
  
  insert()
&lt;/h3&gt;

&lt;p&gt;When inserting a word into the Trie, we'll need to check if the first character of the word already exists as an edge. If the edge exists, then we'll want to use it to add our existing word. If the edge does not exist, then we'll need to create the edge. The method below takes a recursive approach to add the new destination node along with the remaining characters.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Trie&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;word&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="c1"&gt;// if current root has no edge for the char, then we create a&lt;/span&gt;
    &lt;span class="c1"&gt;// new edge for char and point it to a new destination node&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// if there are no more remaining chars in word, we can&lt;/span&gt;
    &lt;span class="c1"&gt;// mark the destination node's terminal property as true&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;isTerminal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// otherwise, recursively insert the remaining chars &lt;/span&gt;
    &lt;span class="c1"&gt;// into destination nodes&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  search()
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;search()&lt;/code&gt; function will tell us whether a word is recognized by the trie. This happens with a traversal down the tree. We start at the root and continually travel through the edges that correspond to the front character of the string. &lt;/p&gt;

&lt;p&gt;The word is recognized by the trie if we traverse down to a terminal node and the string is empty. A word would not be recognized by the trie if the string is empty and we end up on a non-terminal node or if there is a character without an associated edge.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if we've gone through all the characters in word&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// word exists if the current node is a terminal node&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isTerminal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// taking the first character of the string&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;word&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="c1"&gt;// if an edge exists for this char, then recursively check the&lt;/span&gt;
  &lt;span class="c1"&gt;// subtree at the edge's destination with the remaining chars&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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 full code implementation is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Tries may not seem like a super useful or common data structure but they are great for dictionary and word lookup problems. Also, tries can come up in interviews so it's good to get familiar with it. Happy coding and do enjoy some pie with your trie learning!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.interviewcake.com/concept/javascript/trie" rel="noopener noreferrer"&gt;Trie - Interview Cake&lt;/a&gt; &lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Trie" rel="noopener noreferrer"&gt;Trie - Wikipedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://open.appacademy.io/learn/full-stack-online/data-structures-and-algorithms/tries-notes" rel="noopener noreferrer"&gt;Tries - App Academy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://leetcode.com/problems/implement-trie-prefix-tree/" rel="noopener noreferrer"&gt;Implement Trie (Prefix Tree) - Leetcode&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>computerscience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CAP Theorem: Why You Can't Have It All</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Sat, 18 Jul 2020 05:40:43 +0000</pubDate>
      <link>https://dev.to/katkelly/cap-theorem-why-you-can-t-have-it-all-ga1</link>
      <guid>https://dev.to/katkelly/cap-theorem-why-you-can-t-have-it-all-ga1</guid>
      <description>&lt;p&gt;I've been learning the basics of tackling system design problems to better prepare myself for these types of questions in interviews. As a junior developer, system design interviews can be intimidating and difficult to feel adequately prepared for because of the open-ended nature and lack of experience/opportunities to put the skills into practice. Developing large-scale systems is no simple feat!&lt;/p&gt;

&lt;p&gt;In previous posts, I've written about SQL vs. NoSQL and caching, which are small components to designing large-scale systems. Perhaps I'll make all of these posts into a series someday, titled something like "The (Very) Small Building Blocks of a System Design Interview Written For Beginners By a Beginner." &lt;/p&gt;

&lt;p&gt;Thanks for coming to my TED talk! But I do have a topic I want to cover today: CAP Theorem. &lt;strong&gt;CAP stands for consistency, availability, and partition tolerance.&lt;/strong&gt; &lt;strong&gt;CAP theorem is the concept that it is impossible for a distributed software system to guarantee all three properties; you can only have two of the three&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;When designing your distributed data store, you will have to consider tradeoffs and the needs of your system so you can choose a data management system that will deliver on the properties your application needs most. &lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed System
&lt;/h3&gt;

&lt;p&gt;What's a distributed system? It's a network that stores data on more than one node (either a physical or virtual machine) at the same time. All cloud applications are distributed systems. &lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Clients will see the same data at the same time, regardless of which node they connect to.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;To achieve this, when data is written to one node, it must be immediately replicated or forwarded to all of the other nodes in the system before the write is considered a "success".&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If a client makes a request for data, they will get a response even if one or more nodes are down.&lt;/strong&gt; All of the remaining working nodes in the system will return a valid response for any request. &lt;/p&gt;

&lt;p&gt;This is achieved by replicating data across different servers. &lt;/p&gt;

&lt;h2&gt;
  
  
  Partition Tolerance
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;A partition is when there is a message loss or partial failure between two nodes.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The system will continue to work despite the partition and can sustain any amount of network failure that doesn't result in a failure of the entire network.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;To achieve this, data must be sufficiently replicated across a combination of nodes and networks to keep the system up and running through sporadic outages. &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%2Fraw.githubusercontent.com%2Fkat-star%2Fblog-images%2Fmaster%2Fcap-theorem.001.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fkat-star%2Fblog-images%2Fmaster%2Fcap-theorem.001.jpeg" alt="venn diagram of CAP characteristics and example databases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting a NoSQL Database
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Non-relational/NoSQL databases are the best option for a distributed network application because of its horizontal scalability and distributed nature by design&lt;/strong&gt; (can quickly scale across a vast network with a lot of interconnected nodes). &lt;/p&gt;

&lt;p&gt;NoSQL databases can be classified by the two CAP properties they support:&lt;/p&gt;

&lt;h3&gt;
  
  
  CP Database (Consistency, Partition Tolerance)
&lt;/h3&gt;

&lt;p&gt;CP databases will deliver on consistency and partition tolerance, sacrificing availability. A guarantee of availability cannot occur because if a partition happens between any nodes, the system will have to shut down the inconsistent node until the partition resolves.&lt;/p&gt;

&lt;p&gt;MongoDB is a common NoSQL database that stores data as BSON (binary JSON) documents. It follows a single-master set up where only one primary node receives all the write operations, and the other nodes in the same replica set are secondary nodes that replicate the primary node's data. Typically used for big data and real-time apps running at several different locations, MongoDB follows the CP classification as it resolves network partitions by maintaining consistency at the expense of availability. &lt;/p&gt;

&lt;h3&gt;
  
  
  AP Database (Availability, Partition Tolerance)
&lt;/h3&gt;

&lt;p&gt;AP databases deliver on availability and partition tolerance, sacrificing consistency. A guarantee of consistency can't occur because if a partition happens, all nodes remain available but there is a chance that the affected node may deliver stale data.&lt;/p&gt;

&lt;p&gt;Cassandra is another popular NoSQL database that stores data in a wide-column format. Without a master node (unlike Mongo), all nodes have to be available continuously, and as such it follows the AP classification. It is highly performant at the cost of consistency, though Cassandra does provide consistency eventually.&lt;/p&gt;

&lt;h3&gt;
  
  
  CA Database (Consistency, Availability)
&lt;/h3&gt;

&lt;p&gt;CA databases can deliver on consistency and availability, but cannot accommodate partition tolerance. CA databases are relational/SQL databases. &lt;/p&gt;

&lt;p&gt;As with any of your system design needs, you will have to consider all of the benefits of the different database stores and tradeoffs that will work best for your problem. You should also clarify with the interviewer what type of guarantee they are looking for in the system. Talking through the tradeoffs at every stage is key in a system design interview. Understanding the basics is a great first step in getting more comfortable with system design questions. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/courses/grokking-the-system-design-interview/RMkqx1Egxqz" rel="noopener noreferrer"&gt;CAP Theorem - Grokking the System Design Interview (paid resource)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.ibm.com/cloud/learn/cap-theorem" rel="noopener noreferrer"&gt;CAP Theorem - IBM&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rails Caching, Pt. 2</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Fri, 10 Jul 2020 07:04:25 +0000</pubDate>
      <link>https://dev.to/katkelly/rails-caching-pt-2-2c68</link>
      <guid>https://dev.to/katkelly/rails-caching-pt-2-2c68</guid>
      <description>&lt;p&gt;Last week I covered some &lt;a href="https://dev.to/katkelly/rails-caching-pt-1-2bpa"&gt;Ruby on Rails caching basics&lt;/a&gt; such as page, action, and fragment caching and how you can set up a cache on your application in development to test it out. Rails offers caching features out of the box so it's simple to dip your toe into the world of caching.&lt;/p&gt;

&lt;p&gt;For this post, I wanted to look at Cache Stores, as well as some other caching techniques I didn't cover last week. &lt;/p&gt;

&lt;h2&gt;
  
  
  Other Rails Caching Techniques
&lt;/h2&gt;

&lt;p&gt;I previously covered &lt;strong&gt;page caching&lt;/strong&gt; (cached endpoints are short-circuited by the web server and don't go through your Rails stack but not good with before filters like authentication), &lt;strong&gt;action caching&lt;/strong&gt; (web request hits the Rails stack so those before filters can be run before cache data is served), and &lt;strong&gt;fragment caching&lt;/strong&gt; (default Rails caching that's good for fragments and partials). &lt;/p&gt;

&lt;p&gt;Here a few more caching methods:&lt;/p&gt;

&lt;h3&gt;
  
  
  Russian Doll Caching
&lt;/h3&gt;

&lt;p&gt;Russian doll caching builds on fragment caching and allows for nesting cached fragments inside other cached fragments. Using the &lt;code&gt;touch&lt;/code&gt; method can tie the models together so that any action that changes &lt;code&gt;updated_at&lt;/code&gt; for the nested/inner record will also change it for the associated/outer record, making sure the cache is updated and not providing any stale data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Destination&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:activities&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Activity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;touch: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% cache &lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
  &amp;lt;% render destination.activities %&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  SQL Caching
&lt;/h3&gt;

&lt;p&gt;Rails features query caching that caches the result set returned by each query. Returned results from the query are stored in a query cache in memory. If the same query is made again, Rails won't query the database again but pull the result from memory. It's important to keep in mind that the query caches are created at the start of an action and destroyed at the end of that action. If you require queries to be stored in a more persistent manner, you can do so with low level caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Low-level Caching
&lt;/h3&gt;

&lt;p&gt;There may be a situation where you'd rather cache certain values or a query instead of just view fragments. Rails caching works great for storing any kind of information. This is where low-level caching comes in.&lt;/p&gt;

&lt;p&gt;A simple and effective way to implement low-level caching is using &lt;code&gt;Rails.cache.fetch&lt;/code&gt;. This method does both reading and writing to the cache.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If passed only one argument, the key is fetched and the value from the cache is returned&lt;/li&gt;
&lt;li&gt;If a block is passed in, the block will only be executed in the event of a cache miss (the return value of the block will be written to the cache and attached to the key passed in, and the return value will be returned)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="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;Destination&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;top_activity&lt;/span&gt;
    &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"{#cache_key_with_version}/
      top_activity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;expires_in: &lt;/span&gt;&lt;span class="mi"&gt;12&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="no"&gt;Activities&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_activity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When using low-level caching for instance level information, you will need to generate a cache key. &lt;code&gt;cache_key_with_version&lt;/code&gt; method will generate a string key based on the model's class name, id, and updated_at attributes, something like &lt;code&gt;destinations/100-1-202006026193031061005000/top_activity&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Stores
&lt;/h2&gt;

&lt;p&gt;As your cached data has to live somewhere, there are many options for cache stores. &lt;strong&gt;Rails has a default cache store&lt;/strong&gt; that's easy to use though with limitations. If you have caching already toggled on (as referenced in the development &lt;code&gt;config/environments/*.rb&lt;/code&gt; file) the cache will be implemented by default with a default bounded size of 32Mb. You can pass in a &lt;code&gt;:size&lt;/code&gt; option to increase the capacity to the initializer if you wish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;cache_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:memory_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;size: &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;megabytes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For small, low traffic sites with only a handful of server processes and those in development and test environments, this default cache can work well. However, this store is not going to cut it for a large application deployment. &lt;/p&gt;

&lt;h3&gt;
  
  
  MemCacheStore
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MemCacheStore&lt;/code&gt; utilizes Danga's &lt;code&gt;memcached&lt;/code&gt; server and serves as a centralized cache for your app. By default, Rails uses the bundled &lt;code&gt;dalli&lt;/code&gt; gem. This is also the most popular cache store choice for production websites due to its high performance and redundancy with a single, shared cache cluster.&lt;/p&gt;

&lt;p&gt;The cache will be initialized in the relevant &lt;code&gt;config/environments/*.rb&lt;/code&gt; file. In &lt;code&gt;config/environments/production.rb&lt;/code&gt; you can uncomment out the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# Use a different cache store in production.&lt;/span&gt;
  &lt;span class="c1"&gt;# config.cache_store = :mem_cache_store&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You'll need to specify the addresses for all memcached servers in your cluster. If no addresses are provided, the default assumption is that memcached is running on localhost on the default port, which is not an ideal situation for larger websites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;cache_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:mem_cache_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"cache-
1.travelexample.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"cache-2.travelexample.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  RedisCacheStore
&lt;/h3&gt;

&lt;p&gt;Another cache store option is &lt;code&gt;RedisCacheStore&lt;/code&gt;. The Redis cache store makes use of Redis support for automatic eviction when it reaches max memory, letting it behave like a Memcached cache server. &lt;/p&gt;

&lt;p&gt;You'll need to add the &lt;code&gt;redis&lt;/code&gt; gem to your &lt;code&gt;Gemfile&lt;/code&gt;. There is also additional support you can enable with the faster &lt;code&gt;hiredis&lt;/code&gt; connection library by adding its Ruby wrapper to your &lt;code&gt;Gemfile&lt;/code&gt;. The Redis cache store will automatically require and use &lt;code&gt;hiredis&lt;/code&gt; if it's available. And then you'll want to add the configuration to the relevant &lt;code&gt;config/environments/*.rb&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;cache_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:redis_cache_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;url: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REDIS_URL'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Other Cache Stores
&lt;/h3&gt;

&lt;p&gt;There are other cache stores available such as &lt;code&gt;MemoryStore&lt;/code&gt; or &lt;code&gt;FileStore&lt;/code&gt; but you can read more about these and get more information on Rails caching at &lt;a href="https://guides.rubyonrails.org/caching_with_rails.html"&gt;Rails Guides's Caching With Rails&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy caching!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://guides.rubyonrails.org/caching_with_rails.html"&gt;Caching With Rails: An Overview - Rails Guides&lt;/a&gt;&lt;br&gt;
&lt;a href="https://devcenter.heroku.com/articles/caching-strategies"&gt;Caching Strategies for Rails - Heroku&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rails Caching, Pt. 1</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Fri, 03 Jul 2020 22:57:17 +0000</pubDate>
      <link>https://dev.to/katkelly/rails-caching-pt-1-2bpa</link>
      <guid>https://dev.to/katkelly/rails-caching-pt-1-2bpa</guid>
      <description>&lt;p&gt;I've been exploring caching recently, mostly at a high level to better understand the importance of a cache and what goes on behind the scenes (check out &lt;a href="https://dev.to/katkelly/cache-me-if-you-can-ak"&gt;Cache Me If You Can&lt;/a&gt; and &lt;a href="https://dev.to/katkelly/implementing-an-lru-cache-2eh3"&gt;Implementing an LRU Cache&lt;/a&gt; for those posts!). &lt;/p&gt;

&lt;p&gt;It's widely understood that a cache is often the most effective way to boost an application's performance. Web sites that feature a single server and a single database can sustain a load of thousands of concurrent users with caching. &lt;/p&gt;

&lt;p&gt;If you have a Ruby on Rails application, Rails offers a set of caching features out of the box. &lt;strong&gt;This post is going to be part one of a dive into the most common cache techniques and how you can implement caching in development to check it out&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching in Development
&lt;/h2&gt;

&lt;p&gt;Since caching is only enabled by default in the production environment, &lt;strong&gt;we'll need to enable caching directly in the local development environment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But, Rails makes it super easy now (on Rails 5 and above) to set up caching in development. You just need to &lt;strong&gt;run &lt;code&gt;rails dev:cache&lt;/code&gt; to toggle caching on and off&lt;/strong&gt; and if it's turned on, Rails will create a &lt;code&gt;tmp/caching-dev.txt&lt;/code&gt; file. You also won't need to restart the server, as one would have had to do with older versions of Rails. Here is what it looks like in &lt;code&gt;config/environments/development.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Enable/disable caching. By default caching is disabled.&lt;/span&gt;
  &lt;span class="c1"&gt;# Run rails dev:cache to toggle caching.&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tmp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'caching-dev.txt'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_caching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable_fragment_cache_logging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cache_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:memory_store&lt;/span&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="s1"&gt;'Cache-Control'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"public, max-age=&lt;/span&gt;&lt;span class="si"&gt;#{&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;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;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_caching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;

    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cache_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:null_store&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Rails Caching Techniques
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In Rails, there are three different types of caching techniques: page, action, and fragment caching.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Rails provides &lt;strong&gt;fragment caching by default.&lt;/strong&gt; To use page and action caching, you'll have to add these specific &lt;code&gt;actionpack&lt;/code&gt; gems to our Gemfile. &lt;/p&gt;

&lt;h3&gt;
  
  
  Page Caching
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Page caching is a cache approach that stores response bodies in files that the web server can access.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A request to endpoint A arrives&lt;/li&gt;
&lt;li&gt;Its response is determined and gets stored in a file B&lt;/li&gt;
&lt;li&gt;Next time A is requested, the web server sends B directly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It only applies to &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;HEAD&lt;/code&gt; requests with response code 200. This can result in a quick response because the &lt;strong&gt;cached endpoints are short-circuited by the web server and don't even reach your Rails application.&lt;/strong&gt; However, this approach only works for pages that don't need to go through the entire Rails stack. Anything that involves authentication and account-based systems are not good contenders.&lt;/p&gt;

&lt;p&gt;As of Rails 4, page caching has been removed, but you can access and use it by adding &lt;code&gt;actionpack-page_caching&lt;/code&gt; to your &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Action Caching
&lt;/h3&gt;

&lt;p&gt;Action caching is similar to page caching except the incoming web request hits the Rails stack through Action Pack so that any authentication and before filters can be run before the data in the cache is served. &lt;/p&gt;

&lt;p&gt;As of Rails 4, action caching has been removed, but you can access and use it by adding &lt;code&gt;actionpack-action_caching&lt;/code&gt; to your &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragment Caching
&lt;/h2&gt;

&lt;p&gt;By default, Rails offers fragment caching. Depending on the needs of your web application, you can utilize fragment caching to cache different parts of the page. This allows flexibility in what parts you want cached and when it should expire. Fragment caching lets a fragment of view logic (partials, widgets, etc.) to be wrapped in a cache block and served out of the cache store when the next request is made. &lt;/p&gt;

&lt;p&gt;As an example, if you have a travel app and wanted to cache each destination on a page, the code could like something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;% @destinations.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;destination&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
  &amp;lt;% cache destination do %&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% render &lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
  &amp;lt;% end %&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rails will write a new cache entry with a unique key when your app gets its first request to this page. The key will resemble the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&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;destinations&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="mi"&gt;202006026193031061005000&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bea67108094918eeba42cd4a6e786901&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The number after destinations is the &lt;code&gt;product_id&lt;/code&gt; followed by a timestamp value of the &lt;code&gt;updated_at&lt;/code&gt; attribute of the destination record. This timestamp ensures that Rails is not serving stale data. If &lt;code&gt;updated_at&lt;/code&gt; has changed, a new key will be generated and Rails will write a new cache to that key. The old key won't be used again. This is key-based expiration in a nutshell.&lt;/p&gt;

&lt;p&gt;If the view fragment itself changes (if the HTML changes) the cache fragment will also be expired.&lt;/p&gt;

&lt;p&gt;You can also conditionally cache a fragment using &lt;code&gt;cache_if&lt;/code&gt; or &lt;code&gt;cache_unless&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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_if &lt;/span&gt;&lt;span class="n"&gt;beachside?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
  &amp;lt;%= render destination %&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Collection Caching
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;render&lt;/code&gt; method also allows you to cache individual templates rendered for a collection. The below example can read all cache templates at once instead of one by one like above using &lt;code&gt;each&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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 &lt;/span&gt;&lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s1"&gt;'destinations/destination'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="ss"&gt;collection: &lt;/span&gt;&lt;span class="vi"&gt;@destinations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;cached: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Tested
&lt;/h3&gt;

&lt;p&gt;When I played around with implementing the cache, my initial page load after all of the database queries was 316ms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Write fragment views/destinations/show:
ea9a60feb104fccbb55d6feb00a7dcb8/hacks/265-20200528222447858679 &lt;span class="o"&gt;(&lt;/span&gt;0.1ms&lt;span class="o"&gt;)&lt;/span&gt;

Rendered destinations/show.html.erb within layouts/
application &lt;span class="o"&gt;(&lt;/span&gt;Duration: 187.9ms | Allocations: 26579&lt;span class="o"&gt;)&lt;/span&gt;

Completed 200 OK &lt;span class="k"&gt;in &lt;/span&gt;316ms &lt;span class="o"&gt;(&lt;/span&gt;Views: 141.6ms | ActiveRecord:
120.6ms | Allocations: 65663&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When I reloaded the page, the time was cut down to 62ms and the fragments were taken from the cache!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;...
Read fragment views/destinations/show:ea9a60feb104fccbb55d6feb00a7dcb8
/hacks/265-20200528222447858679 &lt;span class="o"&gt;(&lt;/span&gt;0.2ms&lt;span class="o"&gt;)&lt;/span&gt;

Rendered destinations/show.html.erb within layouts/
application &lt;span class="o"&gt;(&lt;/span&gt;Duration: 8.2ms | Allocations: 1860&lt;span class="o"&gt;)&lt;/span&gt;

Completed 200 OK &lt;span class="k"&gt;in &lt;/span&gt;62ms &lt;span class="o"&gt;(&lt;/span&gt;Views: 56.9ms | 
ActiveRecord: 2.0ms | Allocations: 29929&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next week, I'm going to look into Rails Cache Stores as well as other caching techniques I didn't cover here. (&lt;em&gt;Edit: &lt;a href="https://dev.to/katkelly/rails-caching-pt-2-2c68"&gt;Rails Caching, Pt. 2&lt;/a&gt; is up!)&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Happy caching!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://guides.rubyonrails.org/caching_with_rails.html"&gt;Caching With Rails: An Overview - Rails Guides&lt;/a&gt;&lt;br&gt;
&lt;a href="https://devcenter.heroku.com/articles/caching-strategies"&gt;Caching Strategies for Rails - Heroku&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Implementing an LRU Cache</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Sat, 27 Jun 2020 23:47:07 +0000</pubDate>
      <link>https://dev.to/katkelly/implementing-an-lru-cache-2eh3</link>
      <guid>https://dev.to/katkelly/implementing-an-lru-cache-2eh3</guid>
      <description>&lt;p&gt;Last week, I wrote about &lt;a href="https://dev.to/katkelly/cache-me-if-you-can-ak"&gt;caching&lt;/a&gt; and discussed different caching approaches and ways to keep your cache data in sync with the database. A cache is a super effective way to make your application or website more performant, as it can store frequently requested data in a fast-retrieval, data storage layer instead of querying the database every time. &lt;/p&gt;

&lt;p&gt;However, a cache is limited in size and memory. To maintain what gets stored in memory, there needs to be a way for the cache to regulate what goes in (cached) and what goes out (evicted).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This post is dedicated to a common cache policy (that often comes up in coding interviews): the Least Recently Used (LRU) cache. An LRU cache will discard the least recently used item in the cache to make space for new item(s).&lt;/strong&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Implementing a Least Recently Used (LRU) cache traditionally involves a hash map and a doubly linked list.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The linked list would have the most-recently used item at the head of the list and the &lt;strong&gt;least-recently used item stored at the tail.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I love Interview Cake's examples of visualizing an LRU cache. Below is the doubly linked list illustrated sweetly (see what I did there?):&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lqlOst82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.interviewcake.com/images/svgs/lru_cache__most_and_least_recently_used_items.svg%3Fbust%3D206" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lqlOst82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.interviewcake.com/images/svgs/lru_cache__most_and_least_recently_used_items.svg%3Fbust%3D206" alt="interview-cake doubly linked list"&gt;&lt;/a&gt;&lt;/p&gt;
Via Interview Cake



&lt;p&gt;At this point, getting the least-recently used item would take O(1) time since we can look at the tail, but accessing any other specific item that's not the tail or head would take O(n) time since we would have to walk through the entire list. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To make lookups efficient, a hash map is used to map items to linked list nodes.&lt;/strong&gt; More sweetness from Interview Cake illustrating this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pCGw_ziQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.interviewcake.com/images/svgs/lru_cache__doubly_linked_list.svg%3Fbust%3D206" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pCGw_ziQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.interviewcake.com/images/svgs/lru_cache__doubly_linked_list.svg%3Fbust%3D206" alt="interview-cake hash map"&gt;&lt;/a&gt;&lt;/p&gt;
Via Interview Cake


&lt;h3&gt;
  
  
  Access and Eviction
&lt;/h3&gt;

&lt;p&gt;Below are the following steps to go through each time an item is accessed in the cache.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look up the item in the hash map&lt;/li&gt;
&lt;li&gt;If the item is the hash map, hooray, it's a "cache hit" and it's already in the cache

&lt;ol&gt;
&lt;li&gt;Find the corresponding linked list node with the hash map &lt;/li&gt;
&lt;li&gt;Move the item's linked list node to the head of the linked list. It's now the most recently used item.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;If the item is not in the hash map, boo, it's a "cache miss" and you'll have to load the item into the cache

&lt;ol&gt;
&lt;li&gt;Cache full? Then an item will have to be evicted (evict the LRU cache item, the tail, by removing it from the linked list and hash map)&lt;/li&gt;
&lt;li&gt;Create a new linked list node for the item and insert it at the head of the linked list&lt;/li&gt;
&lt;li&gt;Add the item to the hash map, with the new node as the value&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;Like I mentioned above, implementing an LRU cache can often come up in coding interviews. Leetcode features an &lt;a href="https://leetcode.com/problems/lru-cache/"&gt;LRU cache problem&lt;/a&gt; where you have to implement &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;put&lt;/code&gt; operations for the cache. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get(key)&lt;/code&gt; gets the value of the key if the key exists in the cache&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;put(key, value)&lt;/code&gt; sets or inserts the value if the key is not already present&lt;/li&gt;
&lt;li&gt;If the cache has reached its capacity, it should invalidate the least recently used item before inserting a new item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my solution below, it features a few classes including &lt;code&gt;LRUCache&lt;/code&gt;, &lt;code&gt;DoublyLinkedList&lt;/code&gt;, and &lt;code&gt;Node&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.interviewcake.com/concept/java/lru-cache"&gt;LRU Cache - Interview Cake&lt;/a&gt;&lt;br&gt;
&lt;a href="https://leetcode.com/problems/lru-cache/"&gt;LRU Cache - Leetcode&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Cache Me If You Can</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Fri, 19 Jun 2020 05:16:06 +0000</pubDate>
      <link>https://dev.to/katkelly/cache-me-if-you-can-ak</link>
      <guid>https://dev.to/katkelly/cache-me-if-you-can-ak</guid>
      <description>&lt;p&gt;Caching is an important process that can improve your website or application’s performance. At a high level, a cache is a data storage layer that acts like short-term memory by storing data that has been recently requested, taking advantage  of the locality of reference principle in which recently requested data will likely be requested again. A cache’s main purpose is to increase data retrieval performance by reducing the number of times the main database/storage layer will need to be queried.&lt;/p&gt;

&lt;p&gt;In this post, I wanted to look into the basics of a cache such as the different approaches to caching, how its data remains consistent with data in a database, and the different eviction policies that determine how things in a cache are removed to free up space.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Approaches
&lt;/h3&gt;

&lt;p&gt;Application caching and database caching are the two main approaches to caching, though most systems will rely greatly on both. Application caching will require direct integration in the application’s code. It typically works by checking if the data requested is in the cache. If not, it will retrieve the data from the database and then write the value into the cache. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LbdNy0hj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lethain.com/static/blog/intro_arch/app_cache.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LbdNy0hj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lethain.com/static/blog/intro_arch/app_cache.png" alt="application cache image"&gt;&lt;/a&gt;&lt;/p&gt;
Via http://lethain.com



&lt;p&gt;The opposite aspect is database caching, where the cache is placed between the application and the database.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sVOCweks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lethain.com/static/blog/intro_arch/database_cache.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sVOCweks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lethain.com/static/blog/intro_arch/database_cache.png" alt="database cache image"&gt;&lt;/a&gt;&lt;/p&gt;
Via http://lethain.com



&lt;h3&gt;
  
  
  Cache Invalidation
&lt;/h3&gt;

&lt;p&gt;There will need to be maintenance to ensure the data located in the cache is consistent with the database, as the database is the single source of truth. If your data is modified in the database, it should be invalidated in the cache. Below are the main schemes used for cache invalidation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write-through cache&lt;/strong&gt;: data is written into the cache and the corresponding database at the same time

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pros&lt;/em&gt;: fast retrieval in the cache and complete data consistency &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;cons&lt;/em&gt;: higher latency for write operations, as the work is done twice&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-around cache&lt;/strong&gt;: data is only written to the database, bypassing the cache

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pros&lt;/em&gt;: reduces the cache from being flooded with write operations that won’t be read&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;cons&lt;/em&gt;: may create a “cache miss” for a read request that will have to be read from the slower backend storage and face higher latency&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-back cache&lt;/strong&gt;: data is only written to the cache initially and then written to permanent storage after specified intervals or under specific conditions

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pros&lt;/em&gt;: low latency and high throughput for a write-intensive application&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;cons&lt;/em&gt;: risk of data loss and inconsistency in the event of a crash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-through cache&lt;/strong&gt;: the cache sits between the application and database, and the application only requests data from the cache

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pros&lt;/em&gt;: good for read-heavy workloads&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;cons&lt;/em&gt;: higher latency and results in a “cache miss” the first time &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Aside&lt;/strong&gt;: the cache is sitting aside the database and the cache will be checked first to see if the data exists. If not, the application will request data from the database and then update to the cache

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pros&lt;/em&gt;: simple implementation, good for read-heavy workloads&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;cons&lt;/em&gt;: possible data inconsistency and results in a “cache miss” the first time &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Cache Eviction Policies
&lt;/h3&gt;

&lt;p&gt;A cache is limited in its size and memory in order to remain performant. In order to maintain what is stored in local memory, there will need to be a way for the cache to regulate what goes in (cached) and what goes out (evicted).&lt;/p&gt;

&lt;p&gt;The most common cache eviction polices are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First In First Out (FIFO)&lt;/strong&gt;: cache acts like a queue and removes the first block accessed without considering how often or how many times it was accessed before&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Last In First Out (LIFO)&lt;/strong&gt;: cache acts like a stack and evicts the block accessed most recently without considering how often or how many times it was accessed before&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Recently Used (LRU)&lt;/strong&gt;: cache will discard the least recently used item&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most Recently Used (MRU)&lt;/strong&gt;: cache will discard the most recently used item&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Frequently Used (LFU)&lt;/strong&gt;: cache will count how often an item is needed and the items that are least used are discarded first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Random Replacement (RR)&lt;/strong&gt;: cache will randomly select an item and discard it to make space when necessary&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is a lot more about caching I couldn't cover so please utilize the resources below for further reading. Next week, I’ll look at implementing an LRU cache. Stay tuned!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/courses/grokking-the-system-design-interview/3j6NnJrpp5p"&gt;Cache Eviction Policies - Grokking the System Design Interview (paid resource)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://lethain.com/introduction-to-architecting-systems-for-scale/"&gt;Introduction to Architecting Systems&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Cache_(computing)"&gt;Cache(computing)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://blog.bluzelle.com/things-you-should-know-about-database-caching-2e8451656c2d"&gt;Things You Should Know About Database Caching&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ACID Properties</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Sat, 13 Jun 2020 08:27:44 +0000</pubDate>
      <link>https://dev.to/katkelly/acid-properties-2142</link>
      <guid>https://dev.to/katkelly/acid-properties-2142</guid>
      <description>&lt;p&gt;Last week, I wrote about &lt;a href="https://dev.to/katkelly/to-sql-or-nosql-2om"&gt;SQL and NoSQL databases&lt;/a&gt;. One of the main differences between the database types is ACID compliancy. &lt;strong&gt;ACID stands for atomicity, consistency, isolation, durability, and describes a set of transaction properties that guarantees database validity even if an error occurs.&lt;/strong&gt; A majority of SQL/relational databases are ACID compliant databases. I wanted to learn more about ACID properties and why it's an important consideration when deciding what database to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Transactions
&lt;/h4&gt;

&lt;p&gt;A quick note about transactions. A transaction is a collection of instructions. All transactions must follow ACID properties in order to guarantee database validity. I'll use banking transactions between customers below to illustrate the 4 properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atomicity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Atomicity ensures that each transaction is treated as a single unit that follows the "all or nothing" rule; a transaction either happens completely or not at all.&lt;/strong&gt; If any part of the transaction fails, the entire transaction will fail.&lt;/p&gt;

&lt;p&gt;For example, customer A wants to withdraw $100 from their account and then deposit it into customer B's account. If any of the instructions fail (insufficient funds or server crashes, etc.), the transaction will fail and any changes will be rolled back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Consistency guarantees that a transaction must be valid before it gets written to the database.&lt;/strong&gt; A transaction is valid when it follows all of the defined rules, including constraints, cascades, triggers, and any combination of these. Inconsistent transactions will result in the database being rolled back to a previous state that complies with the given database rules.&lt;/p&gt;

&lt;p&gt;If customer A wants to withdraw $100 from their account but only has $50 in their account, consistency prevents them from withdrawing the funds and the transaction will be aborted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolation
&lt;/h3&gt;

&lt;p&gt;As transactions are typically executed at the same time (i.e. multiple transactions that read and write to a table at the same time), &lt;strong&gt;isolation sees that each transaction acts as an individual transaction and would receive the same state if the transactions were executed sequentially.&lt;/strong&gt; Isolation is important for concurrency control.&lt;/p&gt;

&lt;p&gt;If customer C has an account balance of $1000 that both customers A and B can make withdrawals from (say $50 and $100, respectively), one of the customers will have to wait until the other customer transaction is finished, in order to avoid inconsistent data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Durability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Durability ensures that once a transaction has been completed and committed, it will remain committed even in the event of a system failure (crash or power failure).&lt;/strong&gt; These completed transactions are stored in non-volatile memory. &lt;/p&gt;

&lt;p&gt;If customer A successfully deposited $500 in their account, this transaction should not disappear if any system failure occurs.&lt;/p&gt;

&lt;p&gt;As I mentioned above, a majority of SQL/relational databases are ACID compliant. NoSQL databases tend to sacrifice ACID compliancy for faster performance. There is strong data reliability and a guarantee that the transactions are safe. &lt;/p&gt;

&lt;p&gt;There may be clear cut scenarios where an ACID-compliant database is the best solution, such as e-commerce, healthcare, financial services apps (when data integrity is of the utmost concern). Yet, there other times where you may want to take other factors into consideration in deciding between a SQL or NoSQL database. &lt;/p&gt;

&lt;p&gt;Now fully understanding what ACID stands for, I feel better informed when having to make database decisions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/ACID"&gt;ACID - Wikipedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.techopedia.com/definition/23949/atomicity-consistency-isolation-durability-acid-database-management-system"&gt;Atomicity Consistency Isolation Durability (ACID) - Techopedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/edpresso/what-are-acid-properties-in-a-database"&gt;What are ACID properties in a database? - Educative&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
    </item>
    <item>
      <title>To SQL or NoSQL</title>
      <dc:creator>Katherine Kelly</dc:creator>
      <pubDate>Sat, 06 Jun 2020 01:22:05 +0000</pubDate>
      <link>https://dev.to/katkelly/to-sql-or-nosql-2om</link>
      <guid>https://dev.to/katkelly/to-sql-or-nosql-2om</guid>
      <description>&lt;p&gt;When working on personal projects or large-scale applications, developers will often have to set up a database layer to persist the data. With all of the different databases out there, there is not a one-size-fits-all database solution and what you choose will depend on your project needs and any tradeoffs considered.&lt;/p&gt;

&lt;p&gt;Below are the two main types of databases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL / relational databases&lt;/strong&gt; - data is structured and database is accessed with SQL (Structured Query Language)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NoSQL / non-relational databases&lt;/strong&gt; - data is unstructured and database is developed to scale and handle many queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a side-by-side breakdown of the two types:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;&lt;/th&gt;
    &lt;th&gt;SQL&lt;/th&gt;
    &lt;th&gt;NoSQL&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;STORAGE&lt;/td&gt;
    &lt;td&gt;Data is structured and stored in tables
&lt;ul&gt;
&lt;li&gt;Each &lt;strong&gt;row&lt;/strong&gt; contains information about one entity (record)&lt;/li&gt;
&lt;li&gt;Each &lt;strong&gt;column&lt;/strong&gt; contains separate data points (attributes)&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
    &lt;td&gt;Data is unstructured, and there are different types of NoSQL databases with different storage models
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document Databases&lt;/strong&gt;: Data is stored in documents and the documents are grouped together in collections. Each document can have a different structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key-Value Stores&lt;/strong&gt;: Data is stored in an array of key-value pairs, with the key acting as an attribute name that is linked to a value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wide-Column Databases&lt;/strong&gt;: Instead of "tables", columnar databases have column families, which are containers for rows. These databases are best used for analyzing large datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph Databases&lt;/strong&gt;: Data is saved in graph structures with nodes (representing entities), properties (information about the entities), and lines (connections between the entities). These are best used to store data whose relations are best represented in a graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
 &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt;DATABASES&lt;/td&gt;
    &lt;td&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: PostgreSQL, MySQL, SQLite, MariaDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other&lt;/strong&gt;: Oracle DB, MS SQL Server&lt;/li&gt;
&lt;/ul&gt; 
&lt;/td&gt;

    &lt;td&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document Databases&lt;/strong&gt;: MongoDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key-Value Stores&lt;/strong&gt;: Redis, Dynamo, Voldemort&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wide-Column Databases&lt;/strong&gt;: Cassandra, HBase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph Databases&lt;/strong&gt;: Neo4J, InfiniteGraph&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
  &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt;SCHEMA&lt;/td&gt;
    &lt;td&gt;
&lt;strong&gt;Fixed schema&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Columns must be decided on and set up before you add any entries/rows&lt;/li&gt;
&lt;li&gt;Each row must have data for each column&lt;/li&gt;
&lt;li&gt;Schema can be altered later, but it will modify the entire database and will go offline to update&lt;/li&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/td&gt;
    &lt;td&gt;
&lt;strong&gt;Dynamic schema&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;New columns can be added on the fly&lt;/li&gt;
Each entry/row equivalent doesn't have to contain data for each column equivalent
&lt;/ul&gt;
&lt;/td&gt;
  &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt; QUERYING &lt;/td&gt;
    &lt;td&gt;Uses SQL to define and manipulate the data&lt;/td&gt;
    &lt;td&gt;Queries are focused on a collection of documents, sometimes called UnQL (Unstructured Query Language)&lt;/td&gt;
  &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt;SCALABILITY&lt;/td&gt;
    &lt;td&gt;
&lt;strong&gt;Database can scale vertically&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Vertical scaling is more costly as it needs more horsepower (CPU, RAM) of the hardware to increase capacity&lt;/li&gt;
&lt;li&gt;Horizontal scaling across multiple servers is possible but it's challenging and time consuming&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
    &lt;td&gt;
&lt;strong&gt;Database can scale horizontally&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Horizontal scaling needs more machines (servers) in the NoSQL database infrastructure to increase capacity, which is cheaper because servers/hardware/cloud hosting is cheap&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
  &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt;RELIABILITY / ACID COMPLIANCY (Atomicity, Consistency, Isolation, Durability)
&lt;/td&gt;
    &lt;td&gt;
&lt;ul&gt;
&lt;li&gt;Majority of SQL databases are ACID compliant&lt;/li&gt;
&lt;li&gt;Strong data reliability and safe guarantee of performing transactions&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
    &lt;td&gt;Majority of NoSQL databases sacrifice ACID compliance for performance and scalability &lt;/td&gt;
  &lt;/tr&gt;

&lt;tr&gt;
    &lt;td&gt;WHEN TO USE&lt;/td&gt;
    &lt;td&gt;
&lt;ul&gt;
&lt;li&gt;When you need to ensure ACID compliance (e-commerce and financial apps, etc)&lt;/li&gt;
&lt;li&gt;The data is structured, unchanging, consistent&lt;/li&gt;
&lt;li&gt;Business is not facing hyper-fast growth that requires more servers&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
    &lt;td&gt;
&lt;ul&gt;
&lt;li&gt;When you don’t want data to become a bottleneck&lt;/li&gt;
&lt;li&gt;Working with big data&lt;/li&gt;
&lt;li&gt;Storing large volumes of data that often have little structure (and can store different types of data together and on the fly)&lt;/li&gt;
&lt;li&gt;Taking advantage of cloud computing and storage because it’s cheaper and can spread out across multiple servers for scalability&lt;/li&gt;
&lt;li&gt;When rapid development is important&lt;/li&gt;

&lt;/ul&gt;
&lt;/td&gt;
  &lt;/tr&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/courses/grokking-the-system-design-interview/YQlK1mDPgpK"&gt;Grokking the System Design Interview - SQL vs. NoSQL &lt;em&gt;(paid resource)&lt;/em&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.mongodb.com/nosql-explained/nosql-vs-sql"&gt;mongoDB - NoSQL vs SQL Databases&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
    </item>
  </channel>
</rss>
