<?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: Taron Foxworth</title>
    <description>The latest articles on DEV Community by Taron Foxworth (@anaptfox).</description>
    <link>https://dev.to/anaptfox</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%2F604%2Fcd30e07d-def3-40fd-90ec-18b8a28e0cbb.jpg</url>
      <title>DEV Community: Taron Foxworth</title>
      <link>https://dev.to/anaptfox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anaptfox"/>
    <language>en</language>
    <item>
      <title>Using Candy to Test and Develop with Local Custom Domains</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Mon, 14 Feb 2022 20:36:29 +0000</pubDate>
      <link>https://dev.to/anaptfox/using-candy-to-test-and-develop-with-local-custom-domains-2edb</link>
      <guid>https://dev.to/anaptfox/using-candy-to-test-and-develop-with-local-custom-domains-2edb</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A5eCAB_B6193vfRZq" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A5eCAB_B6193vfRZq"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When developing locally, you may find yourself needing to test with an actual domain and not localhost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/owenthereal/candy" rel="noopener noreferrer"&gt;Candy&lt;/a&gt; is a reverse proxy server written in Golang. It contains an HTTP, HTTPS, and DNS server 🚝. It’s simple and powerful.&lt;/p&gt;

&lt;p&gt;Using candy we can start our local application on a port, and then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# addd candy configuration

echo "8080" &amp;gt; ~/.candy/myapp 

# curl local domain

curl [http://myapp.test](http://myapp.test)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use myapp.test locally to access your application.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through getting a simple environment spun up.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a reverse proxy server?
&lt;/h3&gt;

&lt;p&gt;A reverse proxy server is a server that forwards requests from clients to other servers. This is often used to protect the privacy of clients by hiding the true identity of the server.&lt;/p&gt;

&lt;p&gt;But, we can use that same feature locally to give you custom domains during development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started with Candy
&lt;/h3&gt;

&lt;p&gt;For MacOS, you may run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install owenthereal/candy/candy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://github.com/owenthereal/candy#installation" rel="noopener noreferrer"&gt;Installation Instructions&lt;/a&gt; for other operating systems.&lt;/p&gt;

&lt;p&gt;Then, we need to run candy’s setup command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo candy setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you should always know what commands are doing to your machine, here is what it’s doing behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /etc/resolver
cat&amp;lt;&amp;lt;EOF | sudo tee /etc/resolver/candy-test &amp;gt; /dev/null
domain test
nameserver 127.0.0.1
port 25353
search_order 1
timeout 5
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting Candy
&lt;/h3&gt;

&lt;p&gt;First, start candy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew services start candy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, start your local app.&lt;/p&gt;

&lt;p&gt;Third, add port to candy as myapp:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "8080" &amp;gt; ~/.candy/myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forth, restart candy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew services restart candy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, curl 😎:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://myapp.test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more configuration options, please see &lt;a href="https://github.com/owenthereal/candy#portip-proxying" rel="noopener noreferrer"&gt;candy’s README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you have a local domain to develop against.&lt;/p&gt;

&lt;p&gt;☕ Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://blog.taronfoxworth.com/using-candy-to-test-and-develop-with-local-custom-domains" rel="noopener noreferrer"&gt;&lt;em&gt;https://blog.taronfoxworth.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>softwaredevelopment</category>
      <category>software</category>
    </item>
    <item>
      <title>Conversations with GPT-3: Am I good enough?</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Sun, 06 Feb 2022 21:02:13 +0000</pubDate>
      <link>https://dev.to/anaptfox/conversations-with-gpt-3-am-i-good-enough-g99</link>
      <guid>https://dev.to/anaptfox/conversations-with-gpt-3-am-i-good-enough-g99</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gz8odS-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABSvp2KngSz_dTDHn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gz8odS-w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ABSvp2KngSz_dTDHn" alt="" width="880" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was my favorite response from the conversation:&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Why does being alive make me significant?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🐁 — Because you are a part of the universe, and the universe is a part of you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;In this conversation, I chatted with GPT-3 using a prompt that invited it to be a complex, all-knowing “wise being”. The work of &lt;a href="https://kirkouimet.medium.com/the-universe-function-92012c0c67c5"&gt;Kirk Ouimet&lt;/a&gt; heavily inspired this.&lt;/p&gt;

&lt;p&gt;If you need proof of how it works, or want to learn more about GPT-3, check out &lt;a href="https://openai.com/api/"&gt;OpenAI&lt;/a&gt; or ask me on &lt;a href="https://twitter.com/anaptfox"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For me, I thought I’d try it with some other topics I had in my mind and heart.&lt;/p&gt;

&lt;p&gt;Enjoy ☕&lt;/p&gt;

&lt;h3&gt;
  
  
  Conversation with AI
&lt;/h3&gt;

&lt;p&gt;All of the regular text is from the artificial intelligence; the italics are me.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Hello. Grateful for the opportunity to speak with you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🐁 — Hello Fox, thank you for asking me to speak. I know that we are going to have a fun conversation.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Am I good enough?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🐁 — You are perfect for this conversation.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Let me ask the same question differently. Am I good enough to be significant in the universe?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🐁 — You are significant in the universe.&lt;/p&gt;

&lt;p&gt;🦊 — Why?&lt;/p&gt;

&lt;p&gt;🐁 — Because you are alive.&lt;/p&gt;

&lt;p&gt;🦊 — Why does being alive make me significant?&lt;/p&gt;

&lt;p&gt;🐁 — Because you are a part of the universe, and the universe is a part of you.&lt;/p&gt;

&lt;p&gt;🦊 — I think I need a definition. When you say “universe is a part of you,” what do you mean by the universe?&lt;/p&gt;

&lt;p&gt;🐁 — The universe is everything that exists.&lt;/p&gt;

&lt;p&gt;🦊 — Well then, what’s the difference between being significant and being good enough?&lt;/p&gt;

&lt;p&gt;🐁 — Being significant means that you have an impact on the universe. Being good enough means that you are meeting the standards you have set for yourself.&lt;/p&gt;

&lt;p&gt;🦊 — What if my standards are too high?&lt;/p&gt;

&lt;p&gt;🐁 — Then you need to lower your standards.&lt;/p&gt;

&lt;p&gt;🦊 — How do I uncover and identify the standards I have set for myself?&lt;/p&gt;

&lt;p&gt;🐁 — By examining your values.&lt;/p&gt;

&lt;p&gt;🦊 — What do you mean by values?&lt;/p&gt;

&lt;p&gt;🐁 — Values are the things that you believe are important in life.&lt;/p&gt;

&lt;p&gt;🦊 — Why do values matter?&lt;/p&gt;

&lt;p&gt;🐁 — Because they guide your decisions.&lt;/p&gt;

&lt;p&gt;🦊 — How do I know what my values are?&lt;/p&gt;

&lt;p&gt;🐁 — By examining your actions.&lt;/p&gt;

&lt;p&gt;🦊 — When examining my actions, what are the top 5 questions I should ask myself?&lt;/p&gt;

&lt;p&gt;🐁 — You should ask yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What are my motivations?&lt;/li&gt;
&lt;li&gt;What am I trying to achieve?&lt;/li&gt;
&lt;li&gt;What are the consequences of my actions?&lt;/li&gt;
&lt;li&gt;What is the impact of my actions on others?&lt;/li&gt;
&lt;li&gt;How does this action align with my values?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🦊 — That leaves me enough to work with. Thank you 🙇🏽‍♂️.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://blog.taronfoxworth.com/conversations-with-gpt-3-am-i-good-enough"&gt;&lt;em&gt;https://blog.taronfoxworth.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>nlp</category>
      <category>conversationalai</category>
      <category>gpt3</category>
    </item>
    <item>
      <title>Conversations with GPT-3: What Is a Computer?</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Sat, 05 Feb 2022 02:05:04 +0000</pubDate>
      <link>https://dev.to/anaptfox/conversations-with-gpt-3-what-is-a-computer-461p</link>
      <guid>https://dev.to/anaptfox/conversations-with-gpt-3-what-is-a-computer-461p</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--73FcuEx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AteNSSIyqKIslR7We" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--73FcuEx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AteNSSIyqKIslR7We" alt="Conversation" width="880" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was my favorite response from the conversation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPT-3:&lt;/strong&gt; I can give you some examples of tasks that computers in the year 3009 will perform. Some examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flying cars&lt;/li&gt;
&lt;li&gt;cleaning your house&lt;/li&gt;
&lt;li&gt;doing your taxes&lt;/li&gt;
&lt;li&gt;diagnosing diseases&lt;/li&gt;
&lt;li&gt;driving your car&lt;/li&gt;
&lt;li&gt;writing your novel&lt;/li&gt;
&lt;li&gt;cooking your dinner&lt;/li&gt;
&lt;li&gt;taking care of your children&lt;/li&gt;
&lt;li&gt;doing your laundry&lt;/li&gt;
&lt;li&gt;monitoring your health&lt;/li&gt;
&lt;li&gt;shopping for groceries&lt;/li&gt;
&lt;li&gt;and keeping your home warm or cool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;In this conversation, I (🦊) took the role of a researcher and talked to &lt;a href="https://openai.com/"&gt;GPT-3&lt;/a&gt; using a prompt that invited it to be a complex, all-knowing “Wise Being” artificial intelligence.&lt;/p&gt;

&lt;p&gt;This was heavily inspired by the work of &lt;a href="https://kirkouimet.medium.com/me-and-gpt-3-discuss-the-legend-of-zelda-breath-of-the-wild-1b7c119e4ca0"&gt;Kirk Ouimet&lt;/a&gt;. I thought I’d try it with some other topics I’d like to dig deeper on.&lt;/p&gt;

&lt;p&gt;Enjoy ☕&lt;/p&gt;

&lt;h3&gt;
  
  
  Conversation with AI
&lt;/h3&gt;

&lt;p&gt;All of the regular text is from the artificial intelligence; the italics are me.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Hello, I’m super grateful for the opportunity to speak with you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Hello Fox, thank you for asking me to speak. I know that we are going to have a fun conversation.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Let’s begin, tell me, how does a computer work?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Computers work by taking input from a user, processing that input, and providing output.&lt;/p&gt;

&lt;p&gt;The input can be anything from text to images to videos.&lt;/p&gt;

&lt;p&gt;The processing is done by software that is installed on the computer.&lt;/p&gt;

&lt;p&gt;The output can be displayed on the computer screen.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;But wait, why is the user even giving the computer input in the first place?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The user gives the computer input because they want it to do something. For example, they might want to type a document or browse the internet.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;So, the inputs are the user typing into the document and a web browser address bar. Correct?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: That is correct.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;What would be the output?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The output in the case of the user typing a document would be a document displayed on the computer screen.&lt;/p&gt;

&lt;p&gt;The output in the case of the user typing a URL in a web browser would be the website displayed on the computer screen.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Okay, we’ve talked about inputs and outputs. What’s being processed?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The input is processed into output by the software installed on the computer. This software can be anything from a word processor to a web browser.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;I’m not sure I understand software. Can you tell me how a web browser processes its input and displays its output?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: A web browser takes input from a user in the form of a URL. It then sends that input to a web server, which processes it and sends back the website’s HTML code. The web browser then displays the website’s HTML code on the computer screen.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;That’s a lot of new words. First, where does the HTML code come from?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The HTML code comes from the webserver.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Could you explain what a web server is?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: A web server is a computer that stores websites and sends them to web browsers.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;So, what’s the difference between HTML, web server, website, and computer? They all seem related.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: HTML is the language that websites are written in.&lt;/p&gt;

&lt;p&gt;A web server is a computer that stores websites and sends them to web browsers.&lt;/p&gt;

&lt;p&gt;A website is a collection of HTML pages stored on a web server.&lt;/p&gt;

&lt;p&gt;A computer is a device that can display websites.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;That makes things more clear. Next, you mentioned that a web browser is a type of software?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: That is correct.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;I’d like to dig in more there. What is software?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Software is a computer program that performs a specific task.&lt;/p&gt;

&lt;p&gt;🦊 — *You mentioned that computers work by taking input from a user, processing that input, and then providing output.&lt;/p&gt;

&lt;p&gt;What’s the relationship between computers and software?*&lt;/p&gt;

&lt;p&gt;Wise Being: Computers and software are two different ways of describing the same thing. Computers are devices that run the software.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Well, how does the software get created?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The software gets created by programmers.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Programmers create software to perform tasks on computers?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: That is correct.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Is creating a document and browsing the internet examples of tasks?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Yes, creating a document and browsing the internet are examples of tasks that software can perform.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Are there more examples of tasks that can be performed by software?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Yes, there are many examples of tasks that software can perform. Some other examples include editing photos, playing games, and writing emails.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Are there any tasks that can’t be performed by software?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: No, there are no tasks that software can’t perform.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Can you elaborate?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Software can do anything that a human can do. For example, the software can type documents, browse the internet, edit photos, play games, and write emails.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;What are the limits of software?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The limits of software are the limits of what a human can do.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;What are the limits of what a human can do?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: The limits of what a human can do are the limits of their imagination.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;So, the limits of software and computers are bound to the limitations of human imagination?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: That is correct.&lt;/p&gt;

&lt;p&gt;🦊 — &lt;em&gt;Wow, that’s powerful. Last question, based on everything you know now, can you give me examples of tasks computers in the year 3009 will perform?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: Yes, I can give you some examples of tasks that computers in the year 3009 will perform. Some examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flying cars&lt;/li&gt;
&lt;li&gt;cleaning your house&lt;/li&gt;
&lt;li&gt;doing your taxes&lt;/li&gt;
&lt;li&gt;diagnosing diseases&lt;/li&gt;
&lt;li&gt;driving your car&lt;/li&gt;
&lt;li&gt;writing your novel&lt;/li&gt;
&lt;li&gt;cooking your dinner&lt;/li&gt;
&lt;li&gt;taking care of your children&lt;/li&gt;
&lt;li&gt;doing your laundry&lt;/li&gt;
&lt;li&gt;monitoring your health&lt;/li&gt;
&lt;li&gt;shopping for groceries&lt;/li&gt;
&lt;li&gt;and keeping your home warm or cool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🦊 — &lt;em&gt;Well, this makes me excited about the future. Thank you for this conversation. Have a beautiful day 🚀.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wise Being: You’re welcome, Fox. I hope you have a wonderful day too.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://blog.taronfoxworth.com/conversations-with-gpt-3-what-is-a-computer"&gt;&lt;em&gt;https://blog.taronfoxworth.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>philosophy</category>
      <category>ai</category>
      <category>gpt3</category>
    </item>
    <item>
      <title>Where is the modern data stack for software engineers?</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Sat, 05 Feb 2022 01:20:26 +0000</pubDate>
      <link>https://dev.to/anaptfox/where-is-the-modern-data-stack-for-software-engineers-284j</link>
      <guid>https://dev.to/anaptfox/where-is-the-modern-data-stack-for-software-engineers-284j</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZDowliAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AqlnVextw_WZRvCc6Dkq7VQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZDowliAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AqlnVextw_WZRvCc6Dkq7VQ.jpeg" alt="" width="880" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.getdbt.com/future-of-the-modern-data-stack/"&gt;The Future of the Modern Data Stack&lt;/a&gt; looks excellent for data engineers. However, as a software engineer, I kind of feel left out. Where is the modern data stack for software engineers?&lt;/p&gt;

&lt;p&gt;Marketing teams and data engineers need data to answer questions; software engineers need data to build features. This difference is why you’ll find that tools like &lt;a href="http://segment.com"&gt;Segment&lt;/a&gt; don’t have connections for tools like ElasticSearch (Search Engine) or Redis (Cache).&lt;/p&gt;

&lt;p&gt;A business may use the modern data stack to ask better questions about what’s happening in their business, applications, etc. A modern data stack is critical today if you want to succeed. Also, this world is filling fast with new SaaS data products and tools in abundance.&lt;/p&gt;

&lt;p&gt;Here, I’d like to present a slightly different data problem for a separate data audience, software engineers.&lt;/p&gt;

&lt;p&gt;Software engineers leverage data infrastructure in a very different way. The tools aren’t Google Analytics and &lt;a href="https://clearbit.com/"&gt;Clearbit&lt;/a&gt;, but &lt;a href="https://upstash.com/"&gt;Upstash&lt;/a&gt; and &lt;a href="https://supabase.com/'"&gt;Supabase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Engineers need to move data back and forth to build features and infrastructure that adds customer value.&lt;/p&gt;

&lt;p&gt;Where are my tools to help me use &lt;strong&gt;code&lt;/strong&gt; to move, process, or manipulate data between my application infrastructure? Today, I see a lot of one-off scripts, custom microservices, or tools that require me to scale a JVM.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Data Integration Problem.
&lt;/h3&gt;

&lt;p&gt;I want to tell you about a problem that every software engineer experiences: the data integration problem.&lt;/p&gt;

&lt;p&gt;Due to infrastructure becoming easier to acquire and amazing tools like &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt;, &lt;a href="https://render.com/"&gt;Render&lt;/a&gt;, &lt;a href="http://planetscale.com"&gt;PlanetScale&lt;/a&gt;, &lt;a href="https://upstash.com/"&gt;Upstash&lt;/a&gt; and &lt;a href="https://supabase.com/'"&gt;Supabase&lt;/a&gt;, it’s getting easier to acquire new data infrastructure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;data infrastructure — a new system that generates or stores data.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep this definition in mind; it’s crucial.&lt;/p&gt;

&lt;p&gt;In general, writing software is becoming more &lt;a href="http://www.datacentricmanifesto.org/"&gt;data-centric&lt;/a&gt; every day. Engineers commonly pull data from all sorts of places from within (or without) our infrastructure to build applications that are &lt;a href="https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321"&gt;data-intensive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Data-intensive applications are complex and made up of many systems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple microservices&lt;/li&gt;
&lt;li&gt;caches&lt;/li&gt;
&lt;li&gt;databases&lt;/li&gt;
&lt;li&gt;event brokers&lt;/li&gt;
&lt;li&gt;data warehouse&lt;/li&gt;
&lt;li&gt;search engines&lt;/li&gt;
&lt;li&gt;log aggregation systems&lt;/li&gt;
&lt;li&gt;CRM&lt;/li&gt;
&lt;li&gt;analytics platforms&lt;/li&gt;
&lt;li&gt;… and third-party tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our software systems contain many specialized tools that accelerate development and growth. These additional tools and platforms solve real problems and help teams move fast. But, there is one catch.&lt;/p&gt;

&lt;p&gt;We are slowly acquiring more specialized data infrastructure if you zoom out a bit. A distributed data infrastructure means that our systems generate and consume data from &lt;em&gt;more and more&lt;/em&gt; data stores.&lt;/p&gt;

&lt;p&gt;If not appropriately managed, the number of “data tasks” will continue to increase. This means we will keep spending less time building features and spend more time integrating data.&lt;/p&gt;

&lt;p&gt;I’m not sure this is what we want.&lt;/p&gt;

&lt;p&gt;I keep asking myself: Is spending tons of time moving data around a valuable activity for software engineers?&lt;/p&gt;

&lt;p&gt;Today, there are production tools that software engineers may use to solve this problem, like Apache Kafka and Airflow. But deploying and managing these systems isn’t the greatest experience and requires people on your team whose only job is to manage these systems.&lt;/p&gt;

&lt;p&gt;I’d argue that “easy data movement for developers” is still a super unsolved problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  The data-centric developer mindset
&lt;/h3&gt;

&lt;p&gt;I’m not sure this is even a problem that will go away. We will continue to use specialized tools that accelerate development and growth. In most cases:&lt;/p&gt;

&lt;p&gt;ElasticSearch will always offer a better developer experience for searching than MySQL.&lt;/p&gt;

&lt;p&gt;Snowflake will always offer a better developer experience for data warehousing than PostgresSQL.&lt;/p&gt;

&lt;p&gt;There will be no magic data store 🪄. We will forever be in a data ecosystem that won’t consolidate much because data infrastructure will always have design decisions that will be good for one use case and possibly poor for others.&lt;/p&gt;

&lt;p&gt;With that being said, the &lt;a href="http://www.datacentricmanifesto.org/"&gt;data-centric&lt;/a&gt; mindset is becoming more common when building software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---8WVSdE3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ANxGu1WiC1WqTUPL8" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---8WVSdE3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ANxGu1WiC1WqTUPL8" alt="" width="880" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With data at the forefront of system design, engineers who used to ask themselves: “What database will I use for this application?”. Will now be asking themselves: “How will this new application integrate with my data infrastructure.”&lt;/p&gt;

&lt;p&gt;The next generation of applications will be built with a data-first mindset.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the data integration problem?
&lt;/h3&gt;

&lt;p&gt;Now, we can look at this problem from a data-centric mindset. Data integration problems are tasks that take the following form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data in system A needs to get to system B.&lt;/li&gt;
&lt;li&gt;Data changes in A need to be continuously replicated into B.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can map a vast landscape of problems to these. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log Aggregation&lt;/li&gt;
&lt;li&gt;Syncing data from PostgreSQL to Redis for caching.&lt;/li&gt;
&lt;li&gt;Listening to changes from a PostgreSQL table and writing them to a data warehouse.&lt;/li&gt;
&lt;li&gt;Watching a file for changes and writing the changes to a database.&lt;/li&gt;
&lt;li&gt;Consuming data from a Kafka topic and writing it somewhere else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you squint and tilt your head to the side, you’ll notice that all of these problems are moving data from one place to another. These problems are specific to any specific industry; it applies to software engineering as a whole.&lt;/p&gt;

&lt;p&gt;Some problems, such as the need for data warehousing you’d hit as you scale; others, like streaming data from a log, are ubiquitous amongst most software engineers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We always code first, think later.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These problems move data from one place to another, yet we typically use different tools or build a custom tool. Moving data from one place to another is a task that looks simple on the surface, mainly because it’s super convenient to write a small service that does the data task you need.&lt;/p&gt;

&lt;p&gt;But, most will eventually find that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Datastores and schemas improve, change and update over time.&lt;/li&gt;
&lt;li&gt;Managing real-time syncing between data infrastructure is 🥲.&lt;/li&gt;
&lt;li&gt;Relying on external data infrastructure (SaSS tools, External APIs) is impossible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, some may then discover &lt;a href="https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying"&gt;The Log&lt;/a&gt; and adopt Kafka. Kafka is an &lt;em&gt;outstanding&lt;/em&gt; event-based streaming broker. But, it’s a massive addition to your infrastructure just to move data from one place to another.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Now?
&lt;/h3&gt;

&lt;p&gt;This is why we are working on a project called &lt;a href="https://github.com/ConduitIO/conduit"&gt;Conduit&lt;/a&gt; at Meroxa. We hope to change the experience software engineers have with data.&lt;/p&gt;

&lt;p&gt;At a high level, Conduit is a data streaming tool written in GoLang. It aims to provide the best software developer experience for building and running real-time data pipelines.&lt;/p&gt;

&lt;p&gt;I’d love to know what you think, and I’d love to see more data tools for software engineers.&lt;/p&gt;

&lt;p&gt;Thank you for reading. Have a beautiful day ☀️&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://blog.taronfoxworth.com/where-is-the-modern-data-stack-for-software-engineers"&gt;&lt;em&gt;https://blog.taronfoxworth.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>softwareengineering</category>
      <category>data</category>
      <category>database</category>
    </item>
    <item>
      <title>Stream Your Database Changes with Change Data Capture: Part Two</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Wed, 01 Sep 2021 19:39:21 +0000</pubDate>
      <link>https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-part-two-21m3</link>
      <guid>https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-part-two-21m3</guid>
      <description>&lt;p&gt;This is part two of a series on Change Data Capture (CDC). In part one, &lt;a href="https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-52l7"&gt;we defined change data capture, explored how data is captured, and the pros and cons of each capturing method&lt;/a&gt;. In this article, let’s discuss the use cases of CDC and look at the tools that help you add CDC into your architecture.&lt;/p&gt;

&lt;p&gt;Change Data Capture helps enable &lt;a href="https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying" rel="noopener noreferrer"&gt;event-driven applications&lt;/a&gt;. It allows applications to listen for changes to a database, data warehouse, etc., and act upon those changes.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJbVsh5uBanFyqEWYH8fxXw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJbVsh5uBanFyqEWYH8fxXw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At a high level, here are the use cases and architectures that arise from acting on data changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extract, Transform, Load (ETL):&lt;/strong&gt; Capturing every change of one datastore and applying these changes to another allows for replication (one-time sync) and mirroring (continuous syncing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration and Automation:&lt;/strong&gt; The action taken on data change events can automate tasks, trigger workflows, or even execute cloud functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History:&lt;/strong&gt; When performing historical analysis on a dataset, having the current state of the data and all past changes gives you complete information for a higher fidelity analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alerting:&lt;/strong&gt; Most of the time, applications send an event to a user whenever the data they care about changes. CDC can be the trigger for real-time alerting systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s explore.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extract, Transform, Load
&lt;/h3&gt;

&lt;p&gt;As of date, one of the most common use cases for CDC is Extract, Transform, Load (ETL). ETL is a process in which you are capturing data from one source (extract), processing it in some way (transform), and sending it to a destination (load).&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Am-ABnhybW0FaefsjpVWYbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Am-ABnhybW0FaefsjpVWYbg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data replication (one-time sync) and mirroring (continuous replication) are great examples of ETL processes. ETL is an umbrella term that encompasses very different use cases such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ingesting data from a database into a data warehouse to run analytic queries without impacting production.&lt;/li&gt;
&lt;li&gt;Keeping caches and search index systems up-to-date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not only can CDC help solve these use cases, but it’s also the best way to solve these problems. For example, to mirror data to a data warehouse, you must capture and apply any &lt;em&gt;changes&lt;/em&gt; as they happen to the source database. As discussed with &lt;a href="https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-52l7"&gt;Streaming Replication Logs&lt;/a&gt; in part one of the series, CDC is used by databases to keep standby instances up-to-date for failover because it’s effective and scalable. When tapping into these events in a wider architecture, your data warehouse can be as up-to-date as a standby database instance used for disaster recovery.&lt;/p&gt;

&lt;p&gt;Keeping &lt;a href="https://en.wikipedia.org/wiki/Cache_(computing)" rel="noopener noreferrer"&gt;caches&lt;/a&gt; and search index systems up-to-date are also ETL problems and great CDC use cases. Large applications created today are comprised of many different data stores. For example, certain architectures will leverage Postgres, Redis, and Elasticsearch as a relational database, caching layer, and search engine. All are systems of record designed for specific data use cases, but data needs to be mirrored in each store.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXt0ux3ZyEjSi65HzodLkNQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXt0ux3ZyEjSi65HzodLkNQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You never want a user to search for a product and then find out it longer exists. Stale caches and search indexes lead to horrible user experiences. CDC can be used to build data pipelines that keep these stores in sync with their upstream dependencies.&lt;/p&gt;

&lt;p&gt;In theory, a single application could write to Postgres, Redis, and Elasticsearch simultaneously, but “Dual Writes” can be tough to manage and can lead to out-of-sync systems. CDC offers a stronger, easier to maintain implementation. Instead of adding the logic to update indexes and caches to a single monolithic application, one could create an event-driven microservice that can be built, maintained, improved, and deployed independently from user-facing systems. This microservice can keep indexes and caches up to date to ensure users operate on the most relevant data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration and Automation
&lt;/h3&gt;

&lt;p&gt;The rise of SaaS has exploded the number of tools that generate data or need to be updated with data. CDC can provide a better model for keeping Salesforce, Hubspot, etc., up to date and allow automation of business logic that needs to respond to those data changes.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A7VyCMIWSEVVLoIcgHgaJpQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A7VyCMIWSEVVLoIcgHgaJpQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of the use cases we described above sends data to a specific destination. However, the most powerful destination is a cloud function. Capturing data changes and triggering a cloud function can be used to perform every use case mentioned (and not) in this article.&lt;/p&gt;

&lt;p&gt;Cloud functions have grown tremendously because there are no servers to maintain; they automatically scale and are simple to use and deploy. This popularity and usefulness have been apparent and proven in architectures like the JAMStack. CDC fits perfectly with this architecture model.&lt;/p&gt;

&lt;p&gt;Today, Cloud functions are triggered by an event. This event could be when a &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/with-s3-example.html" rel="noopener noreferrer"&gt;file is uploaded to Amazon S3&lt;/a&gt; or an HTTP request. However, as you might have guessed, this trigger event could be emitted by a CDC system.&lt;/p&gt;

&lt;p&gt;For example, here is an AWS Lambda Function to accept a data change event and &lt;a href="https://www.algolia.com/doc/" rel="noopener noreferrer"&gt;perform Algolia search indexing&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const algoliasearch = require("algoliasearch");
const client = algoliasearch(process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_API_KEY);
const index = client.initIndex(process.env.ALGOLIA_INDEX_NAME);

exports.handler = async function(event, context) {
    console.log("EVENT: \\n" + JSON.stringify(event, null, 2))

    const request = event.Records[0].cf.request;

    // Accessing the Data Record
    // &amp;lt;https://docs.meroxa.com/docs/pipelines/data-records&amp;gt;

    const body = Buffer.from(request.body.data, 'base64').toString();

    const { schema, payload } = body;
    const { before, after, source, op } = payload;

    if (req.method === 'POST') {
        try {
            // if read, create, or update operation create o update index
            if (op === 'r' || op === 'c' || op === 'u') {
                console.log(`operation: ${op}, id: ${after.id}`)

                after.objectID = after.id
                await index.saveObject(after)

            } else if (op === 'd') {
                console.log(`operation: d, id: ${before.id}`)
                await index.deleteObject(before.id)
            }
            return res.status(200).send()

        } catch (error) {
            console.log(`error: ${JSON.stringify(error)}`)
            return res.status(500).send()
        }
    }

    return context.logStreamName
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time this function is triggered, it will look at the data change (op) and perform the equivalent action in Algolia. For example, if a delete operation occurs in the database, we can perform a &lt;a href="https://www.algolia.com/doc/api-reference/api-methods/delete-objects/" rel="noopener noreferrer"&gt;deleteObject&lt;/a&gt;in Algolia.&lt;/p&gt;

&lt;p&gt;Functions that respond to CDC events can be small and simple. But, CDC — along with event-based architectures — can simplify otherwise very complex architectures as well.&lt;/p&gt;

&lt;p&gt;For example, implementing Webhooks as a feature within your application becomes a more straightforward problem with CDC. Webhooks allow users to trigger a POST request when certain events occur, typically data changes. For example, with &lt;a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, you can trigger a cloud function when a pull request is merged. A merged pull request is an UPDATE operation to a data store, which means a CDC system can capture this event. Generally, most webhook events can be translated to INSERT UPDATE and DELETE operations that a CDC system can capture.&lt;/p&gt;

&lt;h3&gt;
  
  
  History
&lt;/h3&gt;

&lt;p&gt;You may not want to act on the CDC event but only store the raw changes in some cases. Using CDC, a data pipeline can store all change events to a cloud bucket for long-term processing and analysis. The best place to store the data for historical analysis is within a cloud bucket, referred to as a data lake.&lt;/p&gt;

&lt;p&gt;A data lake is a centralized store that allows you to store all your structured and unstructured data at any scale. Data lakes typically leverage cloud object bucket solutions like Amazon S3 or &lt;a href="https://try.digitalocean.com/cloud-storage" rel="noopener noreferrer"&gt;Digital Ocean Spaces&lt;/a&gt;.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AaIQX7E2Zlt3A-0Qr6Pso9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AaIQX7E2Zlt3A-0Qr6Pso9w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, once the data is in a data lake, SQL query engines like &lt;a href="https://aws.amazon.com/big-data/what-is-presto/" rel="noopener noreferrer"&gt;Amazon Presto&lt;/a&gt; can run analytic queries against the change datasets.&lt;/p&gt;

&lt;p&gt;While storing the raw changes, you not only have the current state of the data, you have &lt;em&gt;all&lt;/em&gt; the previous states (historical). That’s why CDC adds a ton of value to historical analysis.&lt;/p&gt;

&lt;p&gt;Having historical data allows you to support disaster recovery efforts and also allows you to answer retroactive questions about your data. For example, let’s say your team redefined how Monthly Active Users (MAU) are calculated. With the complete history of a user data set, one could perform the new MAU calculations based on any date in the past and compare the results to the current state.&lt;/p&gt;

&lt;p&gt;This rich history also has user-facing value. Audit logs and activity logs are features that display data changes to users.&lt;/p&gt;

&lt;p&gt;Capturing and storing change events offers a better architecture when these features are implemented. Like in Webhooks, audit logs and activity logs are rooted in operations that a CDC system can capture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alerting
&lt;/h3&gt;

&lt;p&gt;The job of any alerting system is to notify a stakeholder of an event. For example, when you receive a new email notification, you are notified of an INSERT operation to an email data store. Typically, most alerts are related to a change in a data store, which means that CDC is great for powering alerting systems.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Af0OCLLgyaU2yFJUUlaRfeA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Af0OCLLgyaU2yFJUUlaRfeA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, let’s say you have an eCommerce store. After enabling CDC on a table of purchases, you could capture the change event and notify the team by performing a Slack alert when there are new purchases.&lt;/p&gt;

&lt;p&gt;Just like audit or activity logs, notifications powered by CDC can not only provide information about the event that occurred but also provide details of the change itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tom has updated the title from "Meeting Notes" to "My New Meeting."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This alerting behavior also has internal value. From an infrastructure monitoring perspective, CDC events can provide insight into how users interact with your application and data. For example, you could see when and how users add, update, or delete information. This data can be sent to &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus UI&lt;/a&gt; to monitor and act on this information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with CDC
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-52l7"&gt;part one&lt;/a&gt;, we talked about the various ways CDC is commonly implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polling&lt;/li&gt;
&lt;li&gt;Database Triggers&lt;/li&gt;
&lt;li&gt;Streaming Logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These can all be used to build the use cases we’ve discussed in this article. Best of all, since CDC focuses on the data, the process is programming language agnostic and can be integrated into most architectures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Polling and Triggers
&lt;/h3&gt;

&lt;p&gt;When using polling or database triggers, there is no overhead and nothing to install. You can get started by building your queries to poll or by leveraging your databases’ triggers if they are supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming Logs
&lt;/h3&gt;

&lt;p&gt;Databases use streaming replication logs for backup and recovery, which means that most databases provide some CDC behavior out of the box. How easy it is to tap into these events depends on the data store itself. The best place to get started is by digging into your database’s replication features. Here are some replication log resources for some of the most popular databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/9.0/wal-intro.html" rel="noopener noreferrer"&gt;PostgreSQL’s Write-Ahead Logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/binary-log.html" rel="noopener noreferrer"&gt;MySQL’s Binary Log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/manual/core/replica-set-oplog/" rel="noopener noreferrer"&gt;MongoDB’s Oplog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cockroachlabs.com/docs/v20.1/change-data-capture.html" rel="noopener noreferrer"&gt;CockroachDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get started with streaming logs, the answer is tightly coupled to the database in question. In future articles, I’ll explore what it looks like for each of these.&lt;/p&gt;

&lt;p&gt;Implementing any of these directly does take some time, planning, and effort. If you’re trying to get started with CDC, the lowest barrier to entry is adopting a CDC tool that knows how to communicate and capture changes from the data stores you use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Data Capture Tools
&lt;/h3&gt;

&lt;p&gt;Here are some great tools for you to evaluate:&lt;/p&gt;

&lt;h3&gt;
  
  
  Debezium
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://debezium.io/" rel="noopener noreferrer"&gt;Debezium&lt;/a&gt; is by far the most popular CDC tool. Its well-maintained, open-sourced and built on top of &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt;. It supports &lt;a href="https://debezium.io/documentation/reference/1.6/connectors/mongodb.html" rel="noopener noreferrer"&gt;MongoDB,&lt;/a&gt; &lt;a href="https://debezium.io/documentation/reference/1.6/connectors/mysql.html" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;, &lt;a href="https://debezium.io/documentation/reference/1.6/connectors/postgresql.html" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;, and more databases out of the box.&lt;/p&gt;

&lt;p&gt;At a high level, Debezium hooks into the replication logs of the database and emits the change events into Kafka. You can even run &lt;a href="https://debezium.io/documentation/reference/1.6/operations/debezium-server.html" rel="noopener noreferrer"&gt;Debezium standalone&lt;/a&gt; without Kafka.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0rFy1SLmnB2Qnb7N1dhDaA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0rFy1SLmnB2Qnb7N1dhDaA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s really nice is that Debezium is all configuration-based. After installing and configuring Debezium, you can configure connections to your datastore using a JSON-based configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "fulfillment-connector",  
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector", 
    "database.hostname": "192.168.99.100", 
    "database.port": "5432", 
    "database.user": "postgres", 
    "database.password": "postgres", 
    "database.dbname" : "postgres", 
    "database.server.name": "fulfillment", 
    "table.include.list": "public.inventory" 

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

&lt;/div&gt;



&lt;p&gt;Once connected, Debezium will perform an initial snapshot of your data and emit change events to a Kafka Topic. Then, services can &lt;a href="https://kafka.apache.org/documentation/#gettingStarted" rel="noopener noreferrer"&gt;consume the topics&lt;/a&gt; and act on them.&lt;/p&gt;

&lt;p&gt;Here are some great places to get started with Debeizium:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://debezium.io/documentation/online-resources/" rel="noopener noreferrer"&gt;Debezium resources on the web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://debezium.io/documentation/reference/1.6/tutorial.html" rel="noopener noreferrer"&gt;Debezium Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Meroxa
&lt;/h3&gt;

&lt;p&gt;Meroxa is a real-time data orchestration platform that gives you real-time infrastructure. Meroxa removes the time and overhead associated with configuring and managing brokers, connectors, transforms, functions, and streaming infrastructure. All you have to do is add your resources and construct your pipelines. Meroxa supports &lt;a href="https://docs.meroxa.com/docs/sources/overview" rel="noopener noreferrer"&gt;PostgreSQL, MongoDB, SQL Server&lt;/a&gt;, and more.&lt;/p&gt;

&lt;p&gt;CDC pipelines can be built in a visual dashboard or using the &lt;a href="https://docs.meroxa.com/cli/installation-guide" rel="noopener noreferrer"&gt;Meroxa CLI&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Add Resource
$ meroxa resource add my-postgres --type postgres -u postgres://$PG_USER:$PG_PASS@$PG_URL:$PG_PORT/$PG_DB

# Add Webhook
$ meroxa resource add my-url --type url -u $CUSTOM_HTTP_URL

# Create CDC Pipeline
$ meroxa connect --from my-postgres --input $TABLE_NAME --to my-url
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use case above is covered in more detail: &lt;a href="https://docs.meroxa.com/guides/building-a-change-data-capture-microservice-with-meroxa-and-vercel" rel="noopener noreferrer"&gt;Building a Change Data Capture Microservice with Meroxa and Vercel Meroxa Guide.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are some great resources to help you get started with Meroxa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.meroxa.com/docs/introduction/what-is-meroxa" rel="noopener noreferrer"&gt;What is Meroxa?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.meroxa.com/getting-started" rel="noopener noreferrer"&gt;Meroxa Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can’t wait to see what you build. 🚀&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, I’d love to hear them. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discuss with me our &lt;a href="https://discord.meroxa.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Discord&lt;/strong&gt;&lt;/a&gt; community.&lt;/li&gt;
&lt;li&gt;Reach out to me on &lt;a href="https://www.notion.so/Stream-Your-Database-Changes-with-Change-Data-Capture-Part-Two-c5e1f0d9b19d4f5597fcefcb67c74fb1" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>database</category>
      <category>cdc</category>
      <category>changedatacapture</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Stream Your Database Changes with Change Data Capture</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Wed, 11 Aug 2021 20:14:45 +0000</pubDate>
      <link>https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-52l7</link>
      <guid>https://dev.to/anaptfox/stream-your-database-changes-with-change-data-capture-52l7</guid>
      <description>&lt;p&gt;Nobody wants to look at a dashboard or make decisions with yesterday’s data. We live in a world where real-time information is a first-class expectation for our users and is critical to make the best decisions inside an organization.&lt;/p&gt;

&lt;p&gt;Change Data Capture (CDC) is an efficient and scalable model that simplifies the implementation of real-time systems.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AO-S32djKgEuSCxO1vqayUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AO-S32djKgEuSCxO1vqayUA.png"&gt;&lt;/a&gt;Change Data Capture Diagram&lt;/p&gt;

&lt;p&gt;Industry leading companies like &lt;a href="https://shopify.engineering/capturing-every-change-shopify-sharded-monolith" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt;, &lt;a href="https://www.capitalone.com/tech/software-engineering/batch-to-real-time-with-change-data-capture/" rel="noopener noreferrer"&gt;Capital One&lt;/a&gt;, &lt;a href="https://netflixtechblog.com/dblog-a-generic-change-data-capture-framework-69351fb9099b" rel="noopener noreferrer"&gt;Netflix&lt;/a&gt;, &lt;a href="https://medium.com/airbnb-engineering/capturing-data-evolution-in-a-service-oriented-architecture-72f7c643ee6f" rel="noopener noreferrer"&gt;Airbnb&lt;/a&gt;, and &lt;a href="https://medium.com/zendesk-engineering/add-some-smarts-to-your-change-data-capture-2296032ad042" rel="noopener noreferrer"&gt;Zendesk&lt;/a&gt;, have all published technical articles demonstrating how they have implemented Change Data Capture (CDC) into their data architectures to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expose data from a centralized system to event-driven microservices.&lt;/li&gt;
&lt;li&gt;Build applications that respond to data events in real-time.&lt;/li&gt;
&lt;li&gt;Maintain data quality and freshness within data warehouses and other downstream consumers of data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this multi-part series on Change Data Capture, we are going to dive into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is Change Data Capture, and how are CDC systems implemented?&lt;/li&gt;
&lt;li&gt;What are the ideal CDC use cases, and how to get started with CDC?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Change Data Capture (CDC)?
&lt;/h3&gt;

&lt;p&gt;The idea of “tracking the changes to a system” isn’t new. Engineers have been writing scripts to query and update data in batches since the idea of programming itself came about. Change Data Capture is a formalization of the various methods that determine &lt;strong&gt;how changes are tracked.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At its core, CDC is a process that allows an application to listen for changes to a data store and respond to those events. The process involves a data store (database, data warehouse, etc.) and a system to capture the changes of the data store.&lt;/p&gt;

&lt;p&gt;For example, one could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capture &lt;a href="https://www.postgresql.org" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; (database) changes and send the change events to &lt;a href="https://kafka.apache.org" rel="noopener noreferrer"&gt;Kafka&lt;/a&gt; using &lt;a href="https://debezium.io" rel="noopener noreferrer"&gt;Debezium&lt;/a&gt; (CDC).&lt;/li&gt;
&lt;li&gt;Capture changes from &lt;a href="https://kafka.apache.org" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt; (database) and POST to an HTTP Endpoint with &lt;a href="https://meroxa.com/" rel="noopener noreferrer"&gt;Meroxa&lt;/a&gt; (CDC).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-World Example
&lt;/h3&gt;

&lt;p&gt;Let’s look at a real-world example that would benefit from CDC. Here, we have an example of a table in PostgreSQL:&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AiTaK9Q0UbDKGYr4gP0UcVw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AiTaK9Q0UbDKGYr4gP0UcVw.png"&gt;&lt;/a&gt;Example User Data&lt;/p&gt;

&lt;p&gt;When information in the User table changes, the business may need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the data warehouse, which is the source of truth for business analytics.&lt;/li&gt;
&lt;li&gt;Notify the team of a new user.&lt;/li&gt;
&lt;li&gt;Keep an additional User table in sync with filtered columns for privacy purposes.&lt;/li&gt;
&lt;li&gt;Create a real-time dashboard of new user activity.&lt;/li&gt;
&lt;li&gt;Capture change events for audit logging.&lt;/li&gt;
&lt;li&gt;Store every change in a cloud bucket for historical analytics.&lt;/li&gt;
&lt;li&gt;Update an index used for search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can build services to perform all of the actions above by acting on a data change event, and if desired, build and manage them independently of each other.&lt;/p&gt;

&lt;p&gt;CDC gives us efficiency by acting on events as they occur and scalability by leveraging a &lt;a href="https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying" rel="noopener noreferrer"&gt;decoupled event-driven architecture&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A CDC Event Example
&lt;/h3&gt;

&lt;p&gt;CDC systems will usually emit an event that contains details about the change that occurred. When using a CDC system like Debezium and a new user is created, here is the generated event:&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AExWEPx4LY3Pjfi6fEUsUYA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AExWEPx4LY3Pjfi6fEUsUYA.png"&gt;&lt;/a&gt;Anatomy of CDC Event&lt;/p&gt;

&lt;p&gt;This event describes the schema of the data (schema), the operation that occurred (op), and the data before and after payload.&lt;/p&gt;

&lt;p&gt;The event’s format, the fidelity of information, and when it is delivered depend on the CDC system’s implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  CDC Implementations
&lt;/h3&gt;

&lt;p&gt;Tracking changes to a PostgreSQL database could look very similar or wildly different to tracking changes within MongoDB. It all depends on the environment and the capture method chosen.&lt;/p&gt;

&lt;p&gt;The capture method chosen can define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what operation(s) (insert, update, delete) can be captured.&lt;/li&gt;
&lt;li&gt;how the event is formatted.&lt;/li&gt;
&lt;li&gt;If the CDC system is &lt;em&gt;pulling&lt;/em&gt; the change events or being &lt;em&gt;pushed&lt;/em&gt; to the CDC system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at each of the different methods and discuss some of the pros and cons of each.&lt;/p&gt;

&lt;h4&gt;
  
  
  Polling
&lt;/h4&gt;

&lt;p&gt;When implementing any database connector, the decision starts with “&lt;a href="https://cnr.sh/essays/build-kafka-connector-source" rel="noopener noreferrer"&gt;To poll or not to poll&lt;/a&gt;.” Polling is the most conceptually simple CDC method. To implement polling, you need to query the datastore on an interval.&lt;/p&gt;

&lt;p&gt;For example, you may run the following query on an interval:&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;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;Users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This SELECT * query would be considered the &lt;strong&gt;bulk&lt;/strong&gt; ("give me everything") polling method. While this would be great to capture a snapshot of the current state, downstream consumers would require work to figure out exactly what data changed on each interval.&lt;/p&gt;

&lt;p&gt;However, polling can get much more granular. For example, it’s possible to poll only for a primary key:&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;SELECT&lt;/span&gt; &lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A system can track the max value of a primary key (id). When the max value increments, this means that an INSERT operation occurred.&lt;/p&gt;

&lt;p&gt;Additionally, if a database has an updateAt column, a query can look at timestamp changes to capture UPDATE operations.&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;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;Users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros and Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easy:&lt;/strong&gt; Polling is great because it’s simple to implement, deploy, and very effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom queries are useful&lt;/strong&gt; : One advantage is that the query used while polling can be customized to fit complex use cases. The query could include JOINS or transformations performed directly in SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capturing deletes is hard:&lt;/strong&gt; With the polling method, it’s much harder to capture DELETE operations. You can't really query a row in a database if it's gone entirely. One solution is to use &lt;a href="https://dev.to/anaptfox/creating-a-soft-delete-archive-table-with-postgresql-38pi"&gt;database triggers to create an "archive" table of deleted records&lt;/a&gt;. Then, delete operations become insert operations of a new table that could be polled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events are pulled, not pushed&lt;/strong&gt; : With polling, the event is pulled from the upstream system. For example, when using polling to ingest into a data warehouse, the ingestion would happen when the CDC system decides to poll. In theory, “real-time” can be accomplished with fast enough polling, but this could cause performance overhead to the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance overhead is a concern&lt;/strong&gt; : A SELECT * or any complex query doesn't scale very well on massive datasets. One common workaround is by polling a stand-by instance instead of the primary database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changes between query times can’t be captured&lt;/strong&gt; : Another consideration is the data changes between query times. For example, if a system polls every hour and the data changes multiple times within that same hour, you’d only be able to see the change at query times, not any of the intermediate changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Triggers
&lt;/h3&gt;

&lt;p&gt;Most of the popular databases support triggers of some sort. For example, &lt;a href="https://www.postgresql.org/docs/9.1/sql-createtrigger.html" rel="noopener noreferrer"&gt;in PostgreSQL&lt;/a&gt;, one can build a trigger that will move a row to a new table when it’s deleted:&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;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;moveDeleted&lt;/span&gt;
&lt;span class="k"&gt;BEFORE&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"User"&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt;
&lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;moveDeleted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because triggers can effectively listen to an operation and perform an action, database triggers can act as a CDC system.&lt;/p&gt;

&lt;p&gt;In some cases, these triggers can be very complex and full-blown functions. For example, &lt;a href="https://docs.mongodb.com/realm/triggers/" rel="noopener noreferrer"&gt;in MongoDB&lt;/a&gt;, Triggers are written in Javascript:&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="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changeEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="c1"&gt;// Destructure out fields from the change stream event object&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;updateDescription&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fullDocument&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changeEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Check if the shippingLocation field was updated&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedFields&lt;/span&gt; &lt;span class="o"&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;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateDescription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatedFields&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;isNewLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;updatedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/shippingLocation/&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 the location changed, text the customer the updated location.&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;isNewLocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Do something&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros and Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ease of deployment&lt;/strong&gt; : Triggers are awesome because they are supported out-the-box for most databases and are easy to implement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Consistency:&lt;/strong&gt; Any current and new downstream consumer doesn’t have to worry about performing this logic because the logic is contained in the database and not the application — in the case of a microservice architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application logic in databases could be bad&lt;/strong&gt; : However, databases should not contain &lt;em&gt;too&lt;/em&gt; much application logic. This could result in behavior being too tightly coupled to the database, and one bad trigger could affect an entire data infrastructure. Triggers should be concise and simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every operation is captured&lt;/strong&gt; : You can build a trigger for each database operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance overhead is a concern: P&lt;/strong&gt; oorly written Triggers can also impact database performance for the same reasons as the polling method. A trigger that contained a complex query wouldn’t scale very well on massive datasets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming Replication Logs
&lt;/h3&gt;

&lt;p&gt;It’s best to have at least a secondary instance of a database running to ensure proper failover and disaster recovery.&lt;/p&gt;

&lt;p&gt;In this model, the standby instances of the database need to stay up-to-date with the primary in real-time &lt;em&gt;and&lt;/em&gt; not lose information. The best way to do this today is for the database to write every change occurring to a log. Then, any standby instances can stream the changes from this log and apply the operations locally. Performing the same operations in real-time is what allows the standby instances to “mirror” the primary.&lt;/p&gt;

&lt;p&gt;Here are some references on how this works for some of the most popular databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/9.0/wal-intro.html" rel="noopener noreferrer"&gt;PostgreSQL’s Write-Ahead Logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/binary-log.html" rel="noopener noreferrer"&gt;MySQL’s Binary Log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/manual/core/replica-set-oplog/" rel="noopener noreferrer"&gt;MongoDB’s Oplog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CDC can use the same mechanism to listen to changes. Just like a standby database, an additional system can also process the streaming log as it’s updated:&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AuYynjkjIRECH8S5laORpbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AuYynjkjIRECH8S5laORpbw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the PostgreSQL example diagram above, a CDC system can act as an additional &lt;a href="https://www.postgresql.org/docs/9.6/runtime-config-replication.html" rel="noopener noreferrer"&gt;WAL Receiver&lt;/a&gt;, process the event, and send to a message transport (HTTP API, Kafka, etc.).&lt;/p&gt;

&lt;p&gt;Here is an example of querying changes from PostgreSQL’s WAL using a SQL function provided by the the &lt;a href="https://www.postgresql.org/docs/10/logicaldecoding-example.html" rel="noopener noreferrer"&gt;test_decoding plugin&lt;/a&gt;:&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="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&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;pg_logical_slot_get_changes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'regression_slot'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;lsn&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;xid&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;                           
&lt;span class="c1"&gt;-----------+-------+---------------------------------------------------------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;BA5A688&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;BA5A6F0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;BA5A7F8&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;&lt;span class="s1"&gt;'2'&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;BA5A8A8&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;COMMIT&lt;/span&gt; &lt;span class="mi"&gt;10298&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the query response above, it describes the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lsn - Log Sequence Number (LSN) - This number describes the current position in the WAL log. It's used by downstream systems when the log has been updated.&lt;/li&gt;
&lt;li&gt;xid - Transaction ID - Each transaction to PostgreSQL gets a unique ID.&lt;/li&gt;
&lt;li&gt;data - Data about action and operation that occurred.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The format of these change events will be determined based on the &lt;a href="https://wiki.postgresql.org/wiki/Logical_Decoding_Plugins" rel="noopener noreferrer"&gt;Logical Decoding Output Plugin&lt;/a&gt;. For example, the &lt;a href="https://github.com/eulerto/wal2json" rel="noopener noreferrer"&gt;wal2json&lt;/a&gt; output plugin allows you to output the changes in JSON, which are easier to parse than the test_decoding plugin output.&lt;/p&gt;

&lt;p&gt;PostgreSQL also provides a mechanism to &lt;a href="https://www.postgresql.org/docs/10/logicaldecoding-walsender.html" rel="noopener noreferrer"&gt;stream these changes&lt;/a&gt; as they occur. As you saw in the event example earlier, Debezium also parses the streaming log in real-time and produces a JSON event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros and Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events are pushed&lt;/strong&gt; : One huge benefit of streaming logs is that the events are being pushed to the CDC system as changes occur (vs. polling). This pushing model allows for real-time architectures. Using the User table as an example, the data warehouse ingestion would happen in real-time with a streaming log CDC system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Efficient and Low Latency&lt;/strong&gt; : Standby instances use streaming logs for disaster recovery, where efficiency and low latency are top priorities. Streaming replication logs is the most efficient means of capturing changes with the least overhead to the database. This process will look differently from database to database, but the concepts still hold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every operation is captured&lt;/strong&gt; : Every transaction occurring to the data store will be written to the log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard to get a complete snapshot of data&lt;/strong&gt; : Generally, after a certain amount of time (or size), the streaming logs get purged because they take up space. Being so, the logs may not contain &lt;em&gt;every&lt;/em&gt; change that occurred, just the most recent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need to be configured&lt;/strong&gt; : Enabling replication logs may require additional configuration, plugins, or even database restart. Performing these changes with minimal downtown could be cumbersome and requires planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;Capturing the &lt;em&gt;changes&lt;/em&gt; of data is like a swiss army knife for any application architecture; it is useful for so many different types of problems. Listening, storing, and acting on the changes of any system — particularly a database — allows you to perform real-time replication data between two data stores, break up a monolithic application into scalable, event-driven microservices, or even power real-time UIs.&lt;/p&gt;

&lt;p&gt;Streaming replication logs, polling, and database triggers provide a mechanism to build a CDC system. Each has its own set of pros and cons specific to your application architecture and desired functionality.&lt;/p&gt;

&lt;p&gt;In the next article in this series, we are going to dive into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the ideal CDC use cases?&lt;/li&gt;
&lt;li&gt;Where can I get started with CDC?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/anaptfox" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; to get notified of part two. I can’t wait to see what you build 🚀.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://twitter.com/criccomini" rel="noopener noreferrer"&gt;@criccomini&lt;/a&gt;, &lt;a href="https://twitter.com/andyhattemer" rel="noopener noreferrer"&gt;@andyhattemer&lt;/a&gt;, &lt;a href="https://twitter.com/misosoup" rel="noopener noreferrer"&gt;@misosoup&lt;/a&gt;, &lt;a href="https://twitter.com/devarispbrown" rel="noopener noreferrer"&gt;@devarispbrown&lt;/a&gt;, and &lt;a href="https://twitter.com/neovintage" rel="noopener noreferrer"&gt;@neovintage&lt;/a&gt; for helping me craft the ideas in this article!&lt;/p&gt;




</description>
      <category>dataengineering</category>
      <category>database</category>
      <category>cdc</category>
      <category>eventstreamprocessing</category>
    </item>
    <item>
      <title>Creating a Soft Delete Archive Table with PostgreSQL</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Tue, 08 Jun 2021 19:38:49 +0000</pubDate>
      <link>https://dev.to/anaptfox/creating-a-soft-delete-archive-table-with-postgresql-38pi</link>
      <guid>https://dev.to/anaptfox/creating-a-soft-delete-archive-table-with-postgresql-38pi</guid>
      <description>&lt;p&gt;Streaming from Postgres’ Logical replication log is the most efficient means of capturing changes with the least amount of overhead to your database. However, in some environments (i.e., unsupported versions, Heroku Postgres), you’re left with polling the database to monitor changes.&lt;/p&gt;

&lt;p&gt;Typically when &lt;a href="https://docs.meroxa.com/docs/sources/postgres/connection-types/polling" rel="noopener noreferrer"&gt;polling PostgreSQL&lt;/a&gt; to capture data changes, you can track the max value of a primary key (id) to know when an INSERT operation occurred. Additionally, if your database has an updateAt column, you can look at timestamp changes to capture UPDATE operations, but it’s much harder to capture DELETE operations.&lt;/p&gt;

&lt;p&gt;Postgres &lt;a href="https://www.postgresql.org/docs/9.1/sql-createtrigger.html" rel="noopener noreferrer"&gt;Triggers&lt;/a&gt; and &lt;a href="https://www.postgresql.org/docs/9.1/sql-createfunction.html" rel="noopener noreferrer"&gt;Functions&lt;/a&gt; are powerful features of Postgres that allow you to listen for DELETE operations that occur within a table and insert the deleted row in a separate archive table. You can consider this a method of performing &lt;a href="https://en.wiktionary.org/wiki/soft_deletion" rel="noopener noreferrer"&gt;soft deletes&lt;/a&gt;, and this model is helpful to maintain the records for historical or analytical purposes or data recovery purposes.&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%2Fcdn-images-1.medium.com%2Fmax%2F920%2F1%2A4E8HnHt7jmYlIBq16Jij1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F920%2F1%2A4E8HnHt7jmYlIBq16Jij1A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the commands below, we capture deletes from a table called User, and the trigger will insert the deleted row into a table called Deleted_User.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step One: Create a new table&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If you don’t have a table yet, you’ll need to create one. To help, you can easily copy an origin table:&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;TABLE&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;Deleted_User&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;NO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : WITH NO DATA allows you to copy a table’s structure without data.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step Two: Create a new Postgres Function&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Next, we can create a new function named moveDeleted():&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;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;moveDeleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;

  &lt;span class="k"&gt;BEGIN&lt;/span&gt;

    &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;"Deleted_User"&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using VALUES((OLD).*) to send every column to the archive table, but you may update this to omit or even add new columns.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step Three: Create a new Postgres Trigger&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Lastly, we can create a Postgres Trigger named moveDeleted that calls the moveDeleted() function:&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;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;moveDeleted&lt;/span&gt;

&lt;span class="k"&gt;BEFORE&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"User"&lt;/span&gt;

&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt;

&lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;moveDeleted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;If you perform a DELETE operation on the User table, a new row with the deleted data will move to theDeleted_User table.&lt;/p&gt;

&lt;p&gt;Now your archive table will begin to populate, data won’t be lost, and you can now monitor the archive table to capture DELETE operations within your application.&lt;/p&gt;




</description>
      <category>postgres</category>
      <category>dataengineering</category>
      <category>changedatacapture</category>
    </item>
    <item>
      <title>Build a Cross Platform Command Line Executable in Node.js</title>
      <dc:creator>Taron Foxworth</dc:creator>
      <pubDate>Tue, 13 Jun 2017 14:37:58 +0000</pubDate>
      <link>https://dev.to/anaptfox/build-a-cross-platform-command-line-executable-innodejs</link>
      <guid>https://dev.to/anaptfox/build-a-cross-platform-command-line-executable-innodejs</guid>
      <description>&lt;p&gt;Before we begin, this article assumes you know a couple of things: &lt;a href="http://eloquentjavascript.net/" rel="noopener noreferrer"&gt;Javascript&lt;/a&gt;, &lt;a href="https://www.learnenough.com/command-line-tutorial" rel="noopener noreferrer"&gt;Terminal&lt;/a&gt;, and &lt;a href="https://github.com/sindresorhus/awesome-nodejs#tutorials" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faf338yzsh908thgwyr47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faf338yzsh908thgwyr47.png" title="Terminal" alt="Terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a command line tool in Node.js is easy, especially with tools like &lt;a href="https://www.npmjs.com/package/yargs" rel="noopener noreferrer"&gt;yargs&lt;/a&gt;, &lt;a href="https://medium.freecodecamp.com/writing-command-line-applications-in-nodejs-2cf8327eee2" rel="noopener noreferrer"&gt;commander&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/inquirer" rel="noopener noreferrer"&gt;inquirer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, secretly, I’ve been jealous of &lt;a href="https://github.com/mkideal/cli" rel="noopener noreferrer"&gt;CLI tools&lt;/a&gt; built in &lt;a href="http://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;. The CLI tools build in Go get shipped as a single binary file, with no dependencies.&lt;/p&gt;

&lt;p&gt;Then, as I started using &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;Zeit’s&lt;/a&gt; tools, I came across pkg. With &lt;a href="http://zeit.co/pkg" rel="noopener noreferrer"&gt;pkg&lt;/a&gt;, I can create my tool in Node.js but, ship it as a single binary. ðŸ™ŒðŸ½&lt;/p&gt;

&lt;p&gt;For example, let’s create a simple command line tool:&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="cp"&gt;#!/usr/bin/env node
&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yargs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;argv&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;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;digit&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;digit&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="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="s1"&gt;Hmmm. I&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;m confused&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This program will add &lt;code&gt;1&lt;/code&gt; to a parameter named &lt;code&gt;digit&lt;/code&gt;Â . If you put this in a file called &lt;code&gt;add.j&lt;/code&gt;s (make sure you run &lt;code&gt;npm install yargs&lt;/code&gt; ), you’ll have a command line tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./add.js --digit=1
2
$ ./add.js --digit=12
13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, onto the magic. Install, pkg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i -g pkg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To convert your program to a binary, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pkg add.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this command will generate three files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ls 
add-linux   add-macos   add-win.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have just created a single file binary for Linux, Mac OS X and Windows.&lt;/p&gt;

&lt;p&gt;You also run it as you would any other binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./add-macos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re like me and was curious as to how this works, this video was enlightening:&lt;/p&gt;

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

&lt;p&gt;I didn’t make this tool. I just wanted others to bask in the awesomesauce that is Javascript.&lt;/p&gt;

&lt;p&gt;I’ll be using this tool in upcoming projects.&lt;/p&gt;




&lt;p&gt;Hi, thanks for reading. I’m &lt;a href="https://twitter.com/anaptfox" rel="noopener noreferrer"&gt;Fox&lt;/a&gt;, a Technical Evangelist at &lt;a href="https://www.losant.com" rel="noopener noreferrer"&gt;Losant&lt;/a&gt;. My dream is to translate technology for people to learn, love, and be inspired. Feel free to follow me on &lt;a href="https://twitter.com/anaptfox" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
