<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lucca Sanwald</title>
    <description>The latest articles on Forem by Lucca Sanwald (@datadeer).</description>
    <link>https://forem.com/datadeer</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%2F54444%2F889f1db6-d0d9-4c40-9569-0cbc0f015531.jpeg</url>
      <title>Forem: Lucca Sanwald</title>
      <link>https://forem.com/datadeer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/datadeer"/>
    <language>en</language>
    <item>
      <title>Using External Editors in Godot</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sat, 14 Mar 2026 19:51:55 +0000</pubDate>
      <link>https://forem.com/datadeer/using-godot-with-external-editors-694</link>
      <guid>https://forem.com/datadeer/using-godot-with-external-editors-694</guid>
      <description>&lt;p&gt;Godot: v4.6.stable.official [89cea1439]&lt;/p&gt;

&lt;p&gt;When using Godot with an external Editor, like JetBrains Rider, Godot asks you to confirm every file when re-focusing the Godot Editor.&lt;/p&gt;

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

&lt;p&gt;If you'd like to silently accept these changes, there is useful setting to make that happen.&lt;/p&gt;

&lt;p&gt;In Editor Settings -&amp;gt; Text Editor -&amp;gt; Behaviour.&lt;br&gt;
Set &lt;code&gt;Auto Reload Scripts on External Change&lt;/code&gt; to &lt;code&gt;On&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Note: This doesn't seem to silence the Dialog on scene (&lt;code&gt;.tscn&lt;/code&gt;) file  changes. Also the Editor documentation states that it still displays the Dialog in some edge-cases. But straight forward script changes now no-longer need to be confirmed. 🥳&lt;/p&gt;

</description>
      <category>godot</category>
      <category>godotengine</category>
      <category>productivity</category>
      <category>gdscript</category>
    </item>
    <item>
      <title>Visualizing UV on a Polygon2D in Godot</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sun, 15 Feb 2026 11:53:49 +0000</pubDate>
      <link>https://forem.com/datadeer/visualizing-uv-on-a-polygon2d-in-godot-1e8o</link>
      <guid>https://forem.com/datadeer/visualizing-uv-on-a-polygon2d-in-godot-1e8o</guid>
      <description>&lt;p&gt;Run on: Godot: v4.6.stable.official [89cea1439]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/idkshite/fragment-shader-uv" rel="noopener noreferrer"&gt;https://github.com/idkshite/fragment-shader-uv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to try out Shaders in Godot and struggled with getting UV values in my fragment shader on a &lt;code&gt;Polygon2D&lt;/code&gt;. Here is how managed to get UV values in my Shader.&lt;/p&gt;




&lt;h1&gt;
  
  
  TLDR;
&lt;/h1&gt;

&lt;p&gt;I could only see my shader displayed on the &lt;code&gt;Polygon2D&lt;/code&gt; in my Editor after:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding the shader as a material to the &lt;code&gt;Polygon2D&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;adding a 1x1 px dummy texture to the &lt;code&gt;Polygon2D&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;manually adding UV data to to the &lt;code&gt;Polygon2D&lt;/code&gt; (maps polygon coordinates to 0-&amp;gt;1 UV range &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Step by Step
&lt;/h1&gt;

&lt;p&gt;My setup is a simple 200x200 px square, created with a &lt;code&gt;Polygon2D&lt;/code&gt; Node.&lt;br&gt;
I wanted to visualize the &lt;code&gt;UV.x&lt;/code&gt; value on that square by setting this Shader&lt;br&gt;
&lt;/p&gt;

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

void fragment() {
   COLOR = vec4(UV.x, 0.0, 0.0, 1.0);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as soon as I set that Shader as a Material on the &lt;code&gt;Polygon2D&lt;/code&gt; node, the material-preview displays what I would expect the shader to look like. But in the editor preview the shader doesn't get applied. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsozntquq7lirz4jaoby9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsozntquq7lirz4jaoby9.png" alt="Shader visible in material preview, but not in editor preview" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I applied a 1x1 px png (created in figma) as the Texture of the &lt;code&gt;Polygon2D&lt;/code&gt;. This seems make &lt;code&gt;UV&lt;/code&gt; values available to the shader. Now we see a bright red square, which indicates that &lt;code&gt;UV.x&lt;/code&gt; is &lt;code&gt;1.0&lt;/code&gt;. But that still not what I'd expect. I assumed the &lt;code&gt;UV.x&lt;/code&gt; differs throughout the entire &lt;code&gt;Polygon2D&lt;/code&gt; and isn't uniform.&lt;/p&gt;

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

&lt;p&gt;Now the Data -&amp;gt; UV on my &lt;code&gt;Polygon2D&lt;/code&gt; is still empty. So I have to fill it. &lt;br&gt;
My assumption was, that I could do that with the the Polygon tab at the bottom of the Editor and then Edit -&amp;gt; "Copy Polygon to UV"&lt;br&gt;
But that literally copies over the Polygon coordinates into the UV data. And UV data needs to be represented in a normalized format (0-&amp;gt;1). So after copying the Polygon Coordinates I normalized the UV data by hand.&lt;/p&gt;

&lt;p&gt;Adding UV coordinates and normalizing them by mapping each vertex from world coordinates to the 0→1 UV range.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FS6W4rM4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FS6W4rM4.gif" width="1400" height="875"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it. Now the shader get's displayed. Hope this helps someone out there 🙌&lt;/p&gt;

</description>
      <category>godot</category>
      <category>godotengine</category>
      <category>shader</category>
      <category>gdscript</category>
    </item>
    <item>
      <title>Running Multiple Claude Code Sessions in Parallel with git worktree</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sun, 29 Jun 2025 19:12:50 +0000</pubDate>
      <link>https://forem.com/datadeer/part-2-running-multiple-claude-code-sessions-in-parallel-with-git-worktree-165i</link>
      <guid>https://forem.com/datadeer/part-2-running-multiple-claude-code-sessions-in-parallel-with-git-worktree-165i</guid>
      <description>&lt;p&gt;One way to push the boundaries of Claude Code is to turn a single Claude into many Claudes! This theoretically allows you to &lt;strong&gt;do twice the work&lt;/strong&gt; in the same time it would take to build a single feature.&lt;/p&gt;

&lt;p&gt;But using multiple agents has (at least) one significant problem...&lt;/p&gt;

&lt;p&gt;If both agents work on the same file, all hell breaks loose. They’ll overwrite each other’s edits and manipulate the other agent’s context.&lt;/p&gt;

&lt;p&gt;How do you prevent agents from stepping on each other's toes?&lt;/p&gt;

&lt;p&gt;You need a way to keep their workspaces separate, like putting them into separate rooms of an office to avoid disturbing each other.&lt;/p&gt;

&lt;p&gt;We can create those separate spaces with &lt;a href="https://git-scm.com/docs/git-worktree" rel="noopener noreferrer"&gt;git-worktree&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say I want to implement a small quality of life feature and work on another feature simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use &lt;code&gt;git worktree&lt;/code&gt;?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I navigate to my project folder. &lt;br&gt;
&lt;code&gt;cd /Users/lucca/Godot/mobsters&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I create a separate project version with git worktree.&lt;br&gt;
&lt;code&gt;git worktree add ../mobsters-worktree/find-my-mobster -b feat/find-my-mobster&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I create a separate terminal tab where I navigate to the new worktree folder. &lt;br&gt;
&lt;code&gt;cd ./../mobsters-worktree/find-my-mobster&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I can now start a Claude Code session in the first and second tab and work on separate features. (running &lt;code&gt;claude&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once I'm done, I commit my changes to my repo and navigate back to my main worktree (&lt;code&gt;/Users/lucca/Godot/mobsters&lt;/code&gt;) to remove the linked worktree with &lt;code&gt;git worktree remove ../mobsters-worktree/find-my-mobster&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To find your main worktree, use &lt;code&gt;git worktree list&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not duplicate the folder?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Duplicating your repository folder takes more space than creating a git-worktree "copy".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Git keeps your repository copies in sync. (e.g. fetches happen on all worktrees, git keeps you from checking out the same branch twice)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;Despite the appeal of this parallel working method, it hasn’t become my default yet.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Setting up worktrees takes time. Depending on the project, I have to copy over files that are not checked into version control or install dependencies. Often, it’s not worth it for a change Claude finishes in 10min.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Juggling multiple Claude sessions is like moderating two separate meetings in neighboring conference rooms - you're endlessly ping-ponging between rooms, keeping track of different discussions, and trying to give meaningful input to both groups without losing the thread of either conversation. The mental gymnastics of context switching not only wears me out but makes me wonder how well I'm steering each session. Especially if Claude regularly needs my input on both features. I can benefit from the parallel approach if one feature is long running and lets me focus on the other.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It sucks up tokens like a Dyson V15. This is so far the only way how I exceeded my Claude Pro Subscription Usage. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'd love to hear about your experience using multiple agents and how you deal with the context switch.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>ai</category>
      <category>godot</category>
    </item>
    <item>
      <title>Building an RTS in Godot. What if Claude writes ALL code?</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sun, 22 Jun 2025 20:22:16 +0000</pubDate>
      <link>https://forem.com/datadeer/part-1-building-an-rts-in-godot-what-if-claude-writes-all-code-49f9</link>
      <guid>https://forem.com/datadeer/part-1-building-an-rts-in-godot-what-if-claude-writes-all-code-49f9</guid>
      <description>&lt;h1&gt;
  
  
  Part 1: Building an RTS in Godot. What if Claude writes ALL code?
&lt;/h1&gt;

&lt;p&gt;I challenged myself to build a game in Godot. I have a web-dev background but very little experience with Game Dev. I watched some tutorials, built tiny projects, but never finished a game to share it.&lt;/p&gt;

&lt;p&gt;This is about to change. I'm creating a &lt;a href="https://github.com/DATADEER/mobsters" rel="noopener noreferrer"&gt;pixel art clone&lt;/a&gt; of the lesser-known Real Time Strategy game "&lt;a href="https://en.wikipedia.org/wiki/Gangland_(video_game)" rel="noopener noreferrer"&gt;Gangland&lt;/a&gt;". It wasn't well received by critics (after watching the &lt;a href="https://www.youtube.com/watch?v=CK7HmuRkO-Q" rel="noopener noreferrer"&gt;trailer&lt;/a&gt; I understand why), but as a kid I really enjoyed this pixel mush. There was something captivating about curating your crew of mafiosi to take over the neighborhood with tommy guns and persuasion. I've deliberately decided to start by copying a game to avoid getting stuck in overthinking.&lt;/p&gt;

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

&lt;p&gt;You know what else is exciting? Seeing your own ideas come to life in your own creation. But it takes time and frustration to do that. If you have a full-time job and other responsibilities, you need to find the time and energy to do that. And even then, there are hundreds of distractions that can keep you from working on ambitious projects. Then there is also the mighty force of "fear of failure" (disguised as "perfectionism") that keeps me from building something like this.&lt;/p&gt;

&lt;p&gt;But what if we could avoid some of that time suck and frustration by handing it over to our good friend Claude? Then I could see my own ideas and past impressions come to life, even with my limited time.&lt;/p&gt;

&lt;p&gt;Introducing my experiment: &lt;strong&gt;"What if Claude writes ALL code?"&lt;/strong&gt; This means:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. I use Claude Code for everything I’d typically write down by hand&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I reach for this extreme measure because I hope I will find some exciting truths if I lean all the way into this direction.&lt;/p&gt;

&lt;p&gt;The only exceptions are some game-design related markdown files. Claude needs a ground truth to work with and I can't risk the truth changing behind my back. So the game's rules and ideas are handwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. The brain rot is part of the experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The experiment aims to find out if building the game solely with AI is possible and to learn another workflow on the side.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will my brain rot or will I shift my skills from coding to thinking deeply about the game’s fun aspects?&lt;/li&gt;
&lt;li&gt;Will solely working with agents exhaust or energize me?&lt;/li&gt;
&lt;li&gt;How does context switching affect me?&lt;/li&gt;
&lt;li&gt;How will I handle situations where Claude can't figure out the solution? What are the options?&lt;/li&gt;
&lt;li&gt;Will Claude drift into spaghetti Code?&lt;/li&gt;
&lt;li&gt;Will I learn anything about Game Development through osmosis or&lt;/li&gt;
&lt;li&gt;How do I adjust my workflow for this new meta?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preliminary Results
&lt;/h2&gt;

&lt;p&gt;I'm roughly 8 hours into the project and I've already made some interesting discoveries about building with my fingers glued to the Claude console.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Importance of Clear Context&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLMs are great at whipping out "something" that resembles your request. But whether the result matches my expectation or not seems to largely depend on how precise I phrase my request. Not a huge surprise here. But nevertheless, I see myself writing short unspecific prompts all the time. Sometimes because I'm lazy, but mostly because I assume Claude can get the rest from the surrounding files and subtext.&lt;/p&gt;

&lt;p&gt;But when I have a specific solution in mind, I need to communicate it precisely. That's where manual context provision comes into play.&lt;/p&gt;

&lt;p&gt;I've created a folder where I document the entire game idea in markdown files. This serves as a ground truth for Claude, so I don't have to repeat myself all the time, but also to keep the game coherent for both the AI and me.&lt;/p&gt;

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

&lt;p&gt;This approach has already paid off. When I first started building the game, the context contained conflicting information about how the character can move. Because of this, Claudes first character controller implementation didn't allow the main character to move around freely on the map. But because I've documented the intended behavior in my markdown files, I could easily resolve this misconception by pointing Claude at the right files and rephrasing things slightly.&lt;/p&gt;

&lt;p&gt;Claude Code also draws context from adjacent code files in your project. But if your code doesn’t accurately represent your vision, Claude may draw wrong conclusions. The markdown files help to resolve those ambiguities.&lt;/p&gt;

&lt;p&gt;I'm not yet sure if it's a good idea to separate the markdown files into multiple files, but time will tell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing the limits of Claude Code
&lt;/h2&gt;

&lt;p&gt;My main issue with the current approach is that I’m using Claude Code reactively. I request a neatly defined feature and Claude delivers a usable result in under 5 minutes. This fast feedback loop is great for getting a feel for the tool because, but it leaves me in an awkward position where working on anything else wouldn’t make sense because Claude could be done any second. I’m treating Claude like a quick-response coding assistant, but it could tackle larger, more complex tasks that take real time to complete.&lt;/p&gt;

&lt;p&gt;We’ll explore Claude Code’s limits in the next part of this series!&lt;/p&gt;

&lt;p&gt;I'll keep you updated on what I'm learning about the process of developing a game without manually typing any code. And as a bonus, you'll see how a crappy prototype turns into a (hopefully) fun game!&lt;/p&gt;

</description>
      <category>godot</category>
      <category>gamedev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Postgres Views: The Hidden Security Gotcha in Supabase</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sun, 09 Mar 2025 21:19:45 +0000</pubDate>
      <link>https://forem.com/datadeer/postgres-views-the-hidden-security-gotcha-in-supabase-ckd</link>
      <guid>https://forem.com/datadeer/postgres-views-the-hidden-security-gotcha-in-supabase-ckd</guid>
      <description>&lt;p&gt;When building with Supabase, Postgres Views can be a powerful tool for simplifying complex queries. But they come with a critical security consideration that isn't immediately obvious: &lt;strong&gt;Views bypass Row Level Security (RLS) by default&lt;/strong&gt;, potentially exposing sensitive data even when your tables are properly secured.&lt;/p&gt;

&lt;p&gt;As a reminder: RLS is what allows you to safely query your Supabase database directly from the frontend, without routing through your backend server. But if RLS isn't working on a table, that table is like your phone screen on public transport—anyone who wants to take a glance, can.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Challenge
&lt;/h2&gt;

&lt;p&gt;Even if you've carefully configured RLS policies on your tables, views can create an unintended backdoor because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, views don’t use RLS&lt;/li&gt;
&lt;li&gt;Supabase's RLS policies page doesn't show or warn about exposed views (last checked 09.03.2025)&lt;/li&gt;
&lt;li&gt;Views don't support RLS in the same way tables do&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing Your View's Security
&lt;/h2&gt;

&lt;p&gt;Before deploying any view to production, it's crucial to verify that it properly respects your RLS policies. Here's a quick way to test if your view is secure:&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;// First, sign in as a specific user&lt;/span&gt;
&lt;span class="c1"&gt;// Then try to fetch ALL rows from your view&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// If your view respects RLS, you should only see rows this user has permission to access.&lt;/span&gt;
&lt;span class="c1"&gt;// If you see ALL rows, your view is bypassing RLS! 🚨&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Securing Your Views
&lt;/h2&gt;

&lt;p&gt;To protect your data, you have several options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For Postgres 15+:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;my_view&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;security_invoker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;my_table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This applies the RLS of &lt;code&gt;my_table&lt;/code&gt; to the view you’re creating.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For older Postgres versions:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Create an internal schema: &lt;code&gt;CREATE SCHEMA internal;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Re-create the sensitive view in the internal schema&lt;/li&gt;
&lt;li&gt;Delete the public version of the view&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use Views
&lt;/h2&gt;

&lt;p&gt;Views are particularly valuable when you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplify complex queries that you use frequently&lt;/li&gt;
&lt;li&gt;Add computed columns that can't be generated columns&lt;/li&gt;
&lt;li&gt;Create virtual tables that recalculate with each request&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Active Subscription Status
&lt;/h3&gt;

&lt;p&gt;I recently built a subscription system and wanted to avoid having to write &lt;code&gt;active_until &amp;gt; NOW()&lt;/code&gt; in every query where I'd need to check for active subscriptions. Planning ahead, I first considered adding an &lt;code&gt;is_active&lt;/code&gt; generated column to the table. But I hit a wall: Postgres doesn't allow volatile functions like &lt;code&gt;now()&lt;/code&gt; in generated columns. That's when I turned to views as a solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_subscriptions&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;security_invoker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&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="n"&gt;active_until&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;is_active&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This view has been working perfectly, giving me clean queries while maintaining security through &lt;code&gt;security_invoker&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>supabase</category>
      <category>javascript</category>
      <category>ts</category>
    </item>
    <item>
      <title>Poor man's visual regression testing</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Wed, 22 Jun 2022 07:57:38 +0000</pubDate>
      <link>https://forem.com/datadeer/poor-mans-visual-regression-testing-57a9</link>
      <guid>https://forem.com/datadeer/poor-mans-visual-regression-testing-57a9</guid>
      <description>&lt;p&gt;Let's assume you've made some big changes to some global css styles in your web application.&lt;br&gt;
You're unsure whether these changes broke any of your meticulously crafted pages.&lt;/p&gt;

&lt;p&gt;You could set up automatic visual regression testing on your CI pipeline with tools from the &lt;a href="https://github.com/mojoaxel/awesome-regression-testing"&gt;"Awesome Visual Regression Testing"&lt;/a&gt; list.&lt;br&gt;
That would probably be the safest option. But it requires some setup and time to get used to the tools.&lt;/p&gt;

&lt;p&gt;You don't have time for that right now? Then let me introduce you to...&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Regression Testing
&lt;/h2&gt;

&lt;p&gt;The idea is: &lt;strong&gt;Take a screenshot&lt;/strong&gt; from a known working state of your webapp. For example your production environment. Then take this screenshot and &lt;strong&gt;overlay it&lt;/strong&gt; on top of your potentially broken state of your webapp.&lt;br&gt;
In this example I'm using the chrome plugins&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/screenshot-capture/giabbpobpebjfegnpcclkocepcgockkc"&gt;screenshot-capture&lt;/a&gt; - to get a &lt;strong&gt;screenshot into my clipboard&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi"&gt;PerfectPixel&lt;/a&gt; - to &lt;strong&gt;overlay the screenshot&lt;/strong&gt; on top of the development page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First I configured &lt;a href="https://chrome.google.com/webstore/detail/screenshot-capture/giabbpobpebjfegnpcclkocepcgockkc"&gt;screenshot-capture&lt;/a&gt; to copy the screenshot into my clipboard and to use a different shortcut as the default one (&lt;code&gt;OPTION + S&lt;/code&gt;) was already occupied by &lt;a href="https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi"&gt;PerfectPixel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hhb0eUdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgur.com/mCE76DH.jpg%257D" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hhb0eUdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgur.com/mCE76DH.jpg%257D" alt="no alt tag provided" width="800" height="430"&gt;&lt;/a&gt; screenshot-capture plugin configuration to copy into clipboard&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare your browser
&lt;/h3&gt;

&lt;p&gt;Then I prepare my browser to have both (local and production environment) open in equal sized browser windows.&lt;br&gt;
It's important those pages have the &lt;strong&gt;same viewport size&lt;/strong&gt; as comparing differently sized images will just make the process more complicated.&lt;br&gt;
This also means the devtools need to be closed during the screenshot and comparison.&lt;br&gt;
If the screenshot doesn't have the same size as the viewport of your browser window, you would need to manually position the screenshot later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshot and compare
&lt;/h3&gt;

&lt;p&gt;Next I take a screenshot of my production webapp running on &lt;code&gt;https://idkshite.com&lt;/code&gt; (with &lt;code&gt;OPTION + SHIFT + S&lt;/code&gt;).&lt;br&gt;
This screenshot is now in my clipboard. I can switch to &lt;code&gt;http://localhost:3000/&lt;/code&gt; and open &lt;a href="https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi"&gt;PerfectPixel&lt;/a&gt; to click on the &lt;code&gt;paste from clipboard&lt;/code&gt; link.&lt;br&gt;
Now the screenshot of the reference page (production environment) should sit on top of the viewport of your localhost browser window.&lt;br&gt;
Feel free to play around with the opacity slider to get an impression of how those changes differ.&lt;br&gt;
Or turn your screenshot into a negative with &lt;code&gt;OPTION + i&lt;/code&gt; to get a stronger contrast.&lt;/p&gt;

&lt;p&gt;🎥 &lt;em&gt;Original post contains a &lt;a href="https://cleanshot-cloud-fra.accelerator.net/media/23887/3R1gRpXqGR7WqsB5av4iCsH42mVjZPIAduwZLnrw.mp4"&gt;Video&lt;/a&gt; available on &lt;a href="https://idkshite.com/posts/compare-visual-changes"&gt;idkshite.com&lt;/a&gt;&lt;/em&gt;&lt;br&gt;&lt;br&gt;
In the long run I would probably invest in some automated regression testing, but as a provisional arrangement it's way more reliable than just glancing over visual changes. 👨‍🎨&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>programming</category>
      <category>css</category>
    </item>
    <item>
      <title>Debugging by talking to yourself</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Mon, 20 Jun 2022 06:45:42 +0000</pubDate>
      <link>https://forem.com/datadeer/debugging-by-talking-to-yourself-7ce</link>
      <guid>https://forem.com/datadeer/debugging-by-talking-to-yourself-7ce</guid>
      <description>&lt;p&gt;Sometimes I have to read code that I either didn't write myself or haven't looked at in a while.&lt;br&gt;
This can be a daunting task.&lt;/p&gt;

&lt;p&gt;Where do I start?&lt;br&gt;
How do I prevent getting &lt;strong&gt;lost in details?&lt;/strong&gt;&lt;br&gt;
How do I &lt;strong&gt;keep track&lt;/strong&gt; of all the fractions of code I've already looked at?&lt;br&gt;
How can I &lt;strong&gt;learn&lt;/strong&gt; as much as possible from my endeavour?&lt;br&gt;
How can I &lt;strong&gt;finish&lt;/strong&gt; this task as fast as possible?&lt;/p&gt;

&lt;p&gt;If the code is somehow observable (like a User Interface) I would probably want to observe what the code actually does before understanding the code itself.&lt;br&gt;
Afterwards I identify the files responsible for the interactions seen on screen,&lt;br&gt;
and come up with hypotheses which code component is responsible for which observable interaction on the screen.&lt;br&gt;
But before I've verified my first hypothesis I may already feel &lt;strong&gt;overwhelmed&lt;/strong&gt; by following a logical and trying to understand all its possible outcomes.&lt;br&gt;
This is where my favourite debugging technique comes into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✍️ Talking to yourself in notion
&lt;/h2&gt;

&lt;p&gt;Instead of running through all these logical branches in my head,&lt;br&gt;
I pick the one that seems most relevant to my problem and start &lt;strong&gt;writing down my thought process&lt;/strong&gt; in my favourite note-taking app.&lt;br&gt;
I prefer notion as it supports nesting collapsible text blocks which allows you to hide your nested lines of thought if they become less relevant.&lt;/p&gt;

&lt;p&gt;🎥 &lt;em&gt;Original post contains a &lt;a href="https://cleanshot-cloud-fra.accelerator.net/media/23887/SUOpfagq1hyqBB2PDHb7ApzG7vw7TGQRMDmvZ0MS.mp4" rel="noopener noreferrer"&gt;Video&lt;/a&gt; available on &lt;a href="https://idkshite.com/posts/favourite-debugging-method" rel="noopener noreferrer"&gt;idkshite.com&lt;/a&gt;&lt;/em&gt;&lt;br&gt;&lt;br&gt;
I start with a question and try to answer it by &lt;strong&gt;following my line of thought.&lt;/strong&gt;&lt;br&gt;
Then I move through the code line by line and write down what it does and how it affects what I see on the screen.&lt;/p&gt;

&lt;p&gt;In this example I wanted to find out: &lt;em&gt;"what happens if I click the publish button when creating a new article?"&lt;/em&gt; inside the &lt;a href="https://react-ts-redux-realworld-example-app.netlify.app/#/editor" rel="noopener noreferrer"&gt; React RealWorld App&lt;/a&gt;&lt;a href="https://github.com/angelguzmaning/ts-redux-react-realworld-example-app" rel="noopener noreferrer"&gt; (GitHub)&lt;/a&gt;&lt;br&gt;
If this process brings up new &lt;strong&gt;questions, I write them down&lt;/strong&gt; and try to answer them in a collapsible text block. Sometimes I decide to postpone answering a question.&lt;br&gt;
Then I mark this question with a "🤔" emoji, so I don't forget that I haven't answered it yet.&lt;br&gt;
In this example I asked myself the question: &lt;em&gt;"Why do we set state.submitting flag to true . Which part of the app code reacts to this state? "&lt;/em&gt;&lt;br&gt;
I assumed this flag could trigger something relevant in the code, but it turned out it only disables the editor form.&lt;/p&gt;

&lt;p&gt;Occasionally I skip following a line of thought and &lt;strong&gt;make assumptions&lt;/strong&gt; about how the code works to progress faster. To make sure I don't forget what I skipped, I mark it with a "🙈" emoji.&lt;br&gt;
In my example I assumed that &lt;code&gt;&amp;lt;ArticleEditor disabled={true} .../&amp;gt;&lt;/code&gt; will disable the whole form inside &lt;code&gt;ArticleEditor&lt;/code&gt;. Because this is not relevant for my problem at hand I can safely ignore it until it becomes relevant.&lt;/p&gt;

&lt;p&gt;You may think this is a time-wasting process. Why not go through this in my head instead?&lt;br&gt;
It may be true that it takes a bit longer to write down your thoughts, but it has some undeniable benefits over "keeping everything in my head"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If I get distracted I still &lt;strong&gt;know where to continue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;By writing down what I've done, I always have a &lt;strong&gt;record of the approaches&lt;/strong&gt; I've used to solve the underlying problem.&lt;/li&gt;
&lt;li&gt;I see which part of he code I may have only checked superficially, and I can &lt;strong&gt;come back&lt;/strong&gt; to if it becomes relevant.&lt;/li&gt;
&lt;li&gt;You also know which questions you &lt;strong&gt;haven't answered yet&lt;/strong&gt;. Did you make some hypothesis but never verified them and based your whole debugging process on it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end there is no silver bullet, and I don't find this approach particularly helpful if the task at hand is manageable in size.&lt;br&gt;
But when I feel overwhelmed by a Task this is my go-to approach to &lt;strong&gt;eat the elephant with small bites&lt;/strong&gt; 🐘&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>debugging</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Public and Private key cryptography</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Fri, 17 Jun 2022 19:15:50 +0000</pubDate>
      <link>https://forem.com/datadeer/public-and-private-key-cryptography-57cn</link>
      <guid>https://forem.com/datadeer/public-and-private-key-cryptography-57cn</guid>
      <description>&lt;p&gt;With the power of cryptography, you can turn perfectly readable content into incomprehensible garbage. Great for hiding your secret "guilty pleasure" playlist from prying eyes.&lt;br&gt;
Encryption usually incorporates something you want to encrypt. Let's call it a &lt;code&gt;message&lt;/code&gt; and a &lt;code&gt;key&lt;/code&gt; that allows you to lock (or &lt;code&gt;encrypt&lt;/code&gt;) and unlock (or &lt;code&gt;decrypt&lt;/code&gt;) the &lt;code&gt;message&lt;/code&gt;. The last ingredient is an encryption algorithm that uses your &lt;code&gt;key&lt;/code&gt; to turn your &lt;code&gt;message&lt;/code&gt; into something that doesn't resemble the original &lt;code&gt;message&lt;/code&gt; anymore.&lt;/p&gt;

&lt;p&gt;But the "one key opens one lock" system only works flawlessly if you don't need to share the key with anyone.&lt;br&gt;
Because then, the question arises: How do you safely transfer the &lt;code&gt;key&lt;/code&gt; to a trusted party? Send them an Email? A carrier pigeon? A letter? None of these options sounds terribly convenient or safe.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;public&lt;/code&gt; and &lt;code&gt;private keys&lt;/code&gt; come into play.&lt;/p&gt;
&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Public&lt;/code&gt; and &lt;code&gt;private keys&lt;/code&gt; can be used to hide the content of messages from strangers but expose them to trusted parties. They can also act as a way to verify the integrity of a &lt;code&gt;message&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;Imagine instead of &lt;code&gt;1 key&lt;/code&gt; you know have &lt;code&gt;2 keys&lt;/code&gt;.&lt;/p&gt;

&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c4IoWXqu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgur.com/NvE13bf.jpg%257D" alt="smeagol my private key" width="500" height="499"&gt; Your private key is your own little secret You never share it with anyone

&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S2yKze3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgur.com/0vqg9Y7.jpg%257D" alt="spreading public key" width="576" height="433"&gt; Your public key on the other hand should be openly shared.

&lt;p&gt;Those &lt;code&gt;2 keys&lt;/code&gt; are created from the same function and are inherently connected. You can encrypt messages with your &lt;code&gt;private key&lt;/code&gt; and decrypt them with your &lt;code&gt;public key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But wait? If everyone has your &lt;code&gt;public key&lt;/code&gt;, anyone can decrypt your messages. This doesn't sound secure at all. But stick with me.&lt;/p&gt;

&lt;p&gt;One can also encrypt a &lt;code&gt;message&lt;/code&gt; with your &lt;code&gt;public key&lt;/code&gt; and decrypt it with the matching &lt;code&gt;private key&lt;/code&gt;.&lt;br&gt;
It starts to make more sense if we introduce a second pair of keys for your friend. An example will shed light on this.&lt;/p&gt;

&lt;p&gt;You want to send your &lt;em&gt;"guilty pleasure playlist"&lt;/em&gt; to your friend Mathilda, but you are concerned by the thought that someone could read the playlist's content while it's being transmitted. To protect the &lt;code&gt;message&lt;/code&gt;, you encrypt it with your friends &lt;code&gt;public key&lt;/code&gt;. Now the &lt;code&gt;message&lt;/code&gt; can only be decrypted with her &lt;code&gt;private key&lt;/code&gt;. So only she can read it. Profit!&lt;/p&gt;
&lt;h3&gt;
  
  
  Interactive node.js message encryption
&lt;/h3&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@idkshite/encryption?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Verify message integrity
&lt;/h2&gt;

&lt;p&gt;There is only one problem with this example. If someone interferes with the transmission between you and Mathilda, they can create a new &lt;code&gt;message&lt;/code&gt; with Mathilda's &lt;code&gt;public key&lt;/code&gt; and pretend it is coming from you. What if they add your least favourite song to the playlist? Mathilda will never talk to you again if she finds out you listen to Wham!(I hope you your friends aren't that judgemental)&lt;/p&gt;

&lt;p&gt;But fortunately, your keys can also help you with this challenge.&lt;br&gt;
You remember you're the only person with your &lt;code&gt;private key&lt;/code&gt;? We can use this to our advantage and encrypt your playlist with your &lt;code&gt;private key&lt;/code&gt;. This won't prevent anyone from reading it. But Mathilda can now be sure the &lt;code&gt;message&lt;/code&gt; is coming from you because she can decrypt it with your &lt;code&gt;public key&lt;/code&gt;. If this is not possible anymore, the &lt;code&gt;message&lt;/code&gt; has been tampered with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive node.js message verification
&lt;/h3&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@idkshite/verify-message-integrity?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;br&gt;
There is also a way to combine those two methods to protect the &lt;code&gt;message&lt;/code&gt; from prying eyes and verify &lt;code&gt;message&lt;/code&gt; integrity. But this a story for another post in the future.

&lt;h2&gt;
  
  
  Further Reads
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=GSIDS_lvRv4"&gt;Public Key Cryptography&lt;/a&gt; - Computerphile&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@vrypan/explaining-public-key-cryptography-to-non-geeks-f0994b3c2d5"&gt;Explaining public-key cryptography to non-geeks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>Reveal the hackerman with js getters and setters</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Wed, 15 Jun 2022 18:59:22 +0000</pubDate>
      <link>https://forem.com/datadeer/reveal-the-hackerman-with-js-getters-and-setters-4203</link>
      <guid>https://forem.com/datadeer/reveal-the-hackerman-with-js-getters-and-setters-4203</guid>
      <description>&lt;p&gt;In this example we're observing a realtime hack of your own video game.&lt;br&gt;
Someone managed to sneak some code into your brand new "first-person-hack-and-slay-roguelite-moba" that gives players a pretty high level from the start. You dislike this new "feature" because it takes all the fun out of "the grind for earning xp".&lt;br&gt;
So you sally forth to find the culprit inside your codebase.&lt;/p&gt;

&lt;p&gt;You know that the hacker is somehow directly increasing the level property in your game. You just have to find out how exactly they increased it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Emoji Parade
&lt;/h2&gt;

&lt;p&gt;Just recently you've added a small widget to your game, that logs an "Emoji Parade" onto the screen.&lt;br&gt;
You were quite satisfied with its look. But something tells you this code may do more than just logging an "Emoji Parade".&lt;br&gt;
But how can you prove it? 🤔&lt;/p&gt;

&lt;p&gt;▶️ Run the replit below to see the hack in action&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@idkshite/Assign-Getters-and-Setters?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Getter and Setters
&lt;/h2&gt;

&lt;p&gt;JavaScript offers a way to control the assignment and retrieval of existing object properties.&lt;br&gt;
You can use &lt;code&gt;get&lt;/code&gt;ters and &lt;code&gt;set&lt;/code&gt;tters to "do something" if someone directly accesses the property or assigns something to it.&lt;/p&gt;

&lt;p&gt;To see how the &lt;code&gt;level&lt;/code&gt; changes over time we replace the &lt;code&gt;level&lt;/code&gt; property on the &lt;code&gt;game&lt;/code&gt; with a set and get function.&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;function&lt;/span&gt; &lt;span class="nf"&gt;monkeyPatchLevelProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logTrace&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="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;logTrace&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;trace&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="c1"&gt;// ignore this. This is only relevant for the logs&lt;/span&gt;

      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;level&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;level up 🔥&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;_level&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;_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&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;newLevel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newLevel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isMonkeyPatched&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;// ignore this. This is only relevant for the logs&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;First we define a new variable where the level value can live &lt;code&gt;let _level = game.level;&lt;/code&gt; and set it to the current value of &lt;code&gt;game.level&lt;/code&gt;&lt;br&gt;
Then &lt;code&gt;Object.defineProperty&lt;/code&gt; allows us to change the &lt;code&gt;level&lt;/code&gt; property to a &lt;code&gt;get&lt;/code&gt;ter and &lt;code&gt;set&lt;/code&gt;er.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;get&lt;/code&gt; function we're logging the current level if the &lt;code&gt;game.level&lt;/code&gt; property gets accessed.&lt;br&gt;
We then return the current value of our new &lt;code&gt;_level&lt;/code&gt; variable so the code relying on it still behaves as expected.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;set&lt;/code&gt; function we're only recreating the expected behaviour behind setting &lt;code&gt;game.level&lt;/code&gt; except we're saving the value in &lt;code&gt;_level&lt;/code&gt; instead of &lt;code&gt;game.level&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;▶️ Open Replit and Uncomment // monkeyPatchLevelProperty(game); to see how the getter logs every time someone accessed game.level&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@idkshite/Assign-Getters-and-Setters?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
▶️ Pass in true as a second parameter to monkeyPatchLevelProperty() and you'll see a stacktrace for each time game.level gets accessed&lt;/p&gt;

&lt;p&gt;And this is how we reveal. The hacker is increasing the level &lt;code&gt;+1&lt;/code&gt; every &lt;code&gt;50ms&lt;/code&gt; on &lt;code&gt;line 14&lt;/code&gt; inside &lt;code&gt;"/hack.js"&lt;/code&gt;. 🥸&lt;/p&gt;

&lt;p&gt;🎥 &lt;em&gt;Original post contains a &lt;a href="https://cleanshot-cloud-fra.accelerator.net/media/23887/Gc1SD2QdOT2IWhXzXGpwjLrOiQaX6SAKvslElCpX.mp4" rel="noopener noreferrer"&gt;Video&lt;/a&gt; available on &lt;a href="https://idkshite.com/posts/observe-object-property" rel="noopener noreferrer"&gt;idkshite.com&lt;/a&gt;&lt;/em&gt;  &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Lodash memoize() | Learn how to cache return values with _.memoize()</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Wed, 27 May 2020 17:43:27 +0000</pubDate>
      <link>https://forem.com/datadeer/lodash-memoize-learn-how-to-cache-return-values-with--memoize-3lm6</link>
      <guid>https://forem.com/datadeer/lodash-memoize-learn-how-to-cache-return-values-with--memoize-3lm6</guid>
      <description>&lt;p&gt;Who should watch this video:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to learn &lt;strong&gt;how and why&lt;/strong&gt; to use the &lt;strong&gt;lodash memoize&lt;/strong&gt; function to cache return values and &lt;strong&gt;increase&lt;/strong&gt; your application &lt;strong&gt;performance&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Leave a comment with feedback to help me improve my content.&lt;/p&gt;

</description>
      <category>lodash</category>
      <category>performance</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Lodash get() | Learn how to safely access values with Lodash _.get()</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Wed, 20 May 2020 13:22:26 +0000</pubDate>
      <link>https://forem.com/datadeer/learn-how-to-safely-access-values-with-lodash--get-50b5</link>
      <guid>https://forem.com/datadeer/learn-how-to-safely-access-values-with-lodash--get-50b5</guid>
      <description>&lt;p&gt;Who should watch this video:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to learn &lt;strong&gt;how and why&lt;/strong&gt; to use the &lt;strong&gt;lodash get&lt;/strong&gt; function to access javascript object properties. Start at &lt;a href="https://youtu.be/2NirvSLQhh8?t=43" rel="noopener noreferrer"&gt;00:43&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;If you want to learn how lodash get was implemented and take a look &lt;strong&gt;under the hood&lt;/strong&gt;. Start at &lt;a href="https://youtu.be/2NirvSLQhh8?t=402" rel="noopener noreferrer"&gt;06:42&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Leave a comment with feedback or fill out my &lt;a href="https://lucca.link/yttfld" rel="noopener noreferrer"&gt;3 Questions form&lt;/a&gt; to help me improve my content.&lt;/p&gt;

</description>
      <category>lodash</category>
      <category>bestpractice</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Debounced Aggregated (Buffered) Actions with RxJS 6 or How to stop making your users wait</title>
      <dc:creator>Lucca Sanwald</dc:creator>
      <pubDate>Sat, 22 Jun 2019 16:36:47 +0000</pubDate>
      <link>https://forem.com/datadeer/debounced-aggregated-buffered-actions-with-rxjs-6-3koa</link>
      <guid>https://forem.com/datadeer/debounced-aggregated-buffered-actions-with-rxjs-6-3koa</guid>
      <description>&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/debounced-aggregated-request-osse7" rel="noopener noreferrer"&gt;Full Codesandbox Example&lt;/a&gt;&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;// (1) Add products on click&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&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;Subject&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// (2) Create debounce Observable as notifier for buffer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debounceAddProduct$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

&lt;span class="c1"&gt;// (3) Buffer values until notifier emits a value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceAddProduct$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;span class="c1"&gt;// (4) Receive results&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$Subscriber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscriber&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;saveSelection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// triggers the loading screen&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;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What will I learn?
&lt;/h2&gt;

&lt;p&gt;Sometimes, you don't want to react to a users input immediately and instead wait until he's finished multiple interactions before you save their progress. Find out how to &lt;strong&gt;buffer&lt;/strong&gt; these &lt;strong&gt;interactions&lt;/strong&gt; with &lt;strong&gt;RxJS 6&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it help?
&lt;/h2&gt;

&lt;p&gt;This can make the difference between a tedious user experience. Where you're forced to wait for every single action to be completed. &lt;a href="https://codesandbox.io/s/debounced-aggregated-request-negative-example-jkwz8" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;And a pleasant user experience. Where the application only saves if you have stopped making actions for a certain timespan. &lt;a href="https://codesandbox.io/s/debounced-aggregated-request-osse7" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;(1) Create a new Subject to be able to emit and receive values.&lt;br&gt;
Push selected Products into the &lt;code&gt;AddProductSubject&lt;/code&gt; whenever the &lt;code&gt;onClick&lt;/code&gt; function is called. (in this case; whenever someone clicks on a product)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&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;Subject&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&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;(2) Create the &lt;code&gt;debounceAddProduct$&lt;/code&gt; Observable that only emits a value if no additional values have been added to the &lt;code&gt;AddProductSubject&lt;/code&gt; for &lt;code&gt;1500&lt;/code&gt;ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debounceAddProduct$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(3) Create the &lt;code&gt;AddProduct$&lt;/code&gt; Observable, which buffers any emitted values until &lt;code&gt;debounceAddProduct$&lt;/code&gt; emits a value and therefore closes the buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProductSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceAddProduct$&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;(4) Subscribe to the &lt;code&gt;AddProduct$&lt;/code&gt; Observable and receive the buffered values, whenever the user has stopped selecting products for at least &lt;code&gt;1500&lt;/code&gt;ms&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$Subscriber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AddProduct$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscriber&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;saveSelection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// triggers the loading screen&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;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/osse7"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Any ideas on how to improve this post? Tell me! I'm always grateful for valuable feedback ;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
  </channel>
</rss>
