<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Spencer Pauly</title>
    <description>The latest articles on Forem by Spencer Pauly (@spencerpauly).</description>
    <link>https://forem.com/spencerpauly</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%2F444771%2Fa1d992d5-857e-4bc6-8ce1-d2981b1cd3f9.jpeg</url>
      <title>Forem: Spencer Pauly</title>
      <link>https://forem.com/spencerpauly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/spencerpauly"/>
    <language>en</language>
    <item>
      <title>Introducing awesome-cursor-skills: A list of awesome skills for Cursor!!</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Fri, 10 Apr 2026 16:57:41 +0000</pubDate>
      <link>https://forem.com/spencerpauly/introducing-awesome-cursor-skills-a-list-of-awesome-skills-for-cursor-1a8e</link>
      <guid>https://forem.com/spencerpauly/introducing-awesome-cursor-skills-a-list-of-awesome-skills-for-cursor-1a8e</guid>
      <description>&lt;p&gt;awesome-cursor-skills: &lt;a href="https://github.com/spencerpauly/awesome-cursor-skills" rel="noopener noreferrer"&gt;https://github.com/spencerpauly/awesome-cursor-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Been using many of these cursor skills for a while now. Thought I would bring together in one central place others! Some of my favorites:&lt;/p&gt;

&lt;p&gt;suggesting-cursor-rules - If I get frustrated or suggest the same changes repeatedly, suggest a cursor rule for it.&lt;/p&gt;

&lt;p&gt;screenshotting-changelog - Generate visual before/after PR descriptions by screenshotting UI changes across branches.&lt;/p&gt;

&lt;p&gt;parallel-test-fixing - When multiple tests fail, assign each to a separate subagent that fixes it independently in parallel.&lt;/p&gt;

&lt;p&gt;Enjoy! And please add your own skills I'd appreciate it!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>I Gave Claude Code Access to My Prod Database with MCP</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Sun, 29 Mar 2026 20:09:46 +0000</pubDate>
      <link>https://forem.com/spencerpauly/i-gave-my-ai-access-to-my-prod-database-with-mcp-15c0</link>
      <guid>https://forem.com/spencerpauly/i-gave-my-ai-access-to-my-prod-database-with-mcp-15c0</guid>
      <description>&lt;p&gt;Last week I did something that would've made me uncomfortable six months ago. I opened my Claude Desktop config, added an MCP server URL pointing at my production Postgres database, and told Claude to go look at real customer data.&lt;/p&gt;

&lt;p&gt;Nothing caught fire.&lt;/p&gt;

&lt;p&gt;I've been building QueryBear for a while now, and I'd always been careful to test against staging data, demo databases, seed data. Production was the thing I protected.&lt;/p&gt;

&lt;p&gt;But I kept hitting the same wall. I'd be deep in a debugging thread with Claude, connected to Linear and my codebase, and I'd get 90% of the way to understanding a customer issue. Then I'd tab over to my database client, look up the user, write a couple joins, squint at the results, copy them back into chat. Every single time.&lt;/p&gt;

&lt;p&gt;It's not hard. It's just friction. After doing it fifty times in a week I started thinking: why am I the bottleneck here?&lt;/p&gt;

&lt;p&gt;So I built an MCP server that sits between the AI and my database. The AI doesn't get a connection string. It doesn't get credentials. It gets tool calls, and the server decides what happens.&lt;/p&gt;

&lt;p&gt;The config I added to Claude Desktop was two fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"querybear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.querybear.com/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer qb_live_xxxxx"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I restarted Claude and typed: "How many users signed up in the last 7 days?"&lt;/p&gt;

&lt;p&gt;Three seconds later I had the answer. From prod. Correct.&lt;/p&gt;

&lt;p&gt;I asked it to break signups down by day. Then by referral source. Then I asked it to cross-reference with which users created their first query. Each answer came back fast, and each one was right.&lt;/p&gt;

&lt;p&gt;What surprised me wasn't that it worked. I built the thing. What surprised me was how natural it felt. I wasn't context-switching anymore. I was just asking questions inside the same thread where I was already working.&lt;/p&gt;

&lt;p&gt;The reason I wasn't scared: every query passes through a security pipeline before it touches the database. SQL gets parsed into an AST, only SELECTs pass. Tables get checked against an allowlist. Sensitive columns get stripped. Row limits get enforced by rewriting the query. Timeouts kill anything that runs too long, server-side. The whole thing runs inside a read-only transaction. And everything gets logged.&lt;/p&gt;

&lt;p&gt;The worst case is the AI gets a "query rejected" response. That's a much better failure mode than "oops, that was production."&lt;/p&gt;

&lt;p&gt;Before this, debugging a customer issue meant reading the ticket in my AI thread, tabbing to the database, writing queries, copying results back. Now I paste the ticket and say "look up this user's account and tell me what's going on." Steps 2 through 5 just disappeared.&lt;/p&gt;

&lt;p&gt;I've also started using it for things I wouldn't have bothered querying before. Quick sanity checks during development. "Did that migration actually backfill the new column?" Instead of writing a throwaway query, I just ask.&lt;/p&gt;

&lt;p&gt;I'm still iterating on this. But the core loop of "ask your AI a question about your data and get a real answer" already works, and it's already changed how I work day to day.&lt;/p&gt;

&lt;p&gt;If you want to try it, you can set it up at querybear.com in a couple minutes. And if you've already connected AI to your database some other way, I'm curious how you handled the security side. Still figuring out where the line should be.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>mcp</category>
      <category>postgres</category>
      <category>productivity</category>
    </item>
    <item>
      <title>So, I gave my coding agent direct database access...</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Sun, 22 Mar 2026 19:37:07 +0000</pubDate>
      <link>https://forem.com/spencerpauly/so-i-gave-my-coding-agent-direct-database-access-33ed</link>
      <guid>https://forem.com/spencerpauly/so-i-gave-my-coding-agent-direct-database-access-33ed</guid>
      <description>&lt;p&gt;I've been connecting my coding agent to everything: Datadog logs, Linear, Slack. But, still get bottlenecked at the database.&lt;/p&gt;

&lt;p&gt;I'll be debugging. The LLM can read the stack trace, make a ticket, scan the codebase, but can't introspect the database. So I can't prove what happened in the data.&lt;/p&gt;

&lt;p&gt;At some point I hacked together a repo on my laptop. It generated SQL and talked to the database for me. And it worked better than I expected.&lt;/p&gt;

&lt;p&gt;But, It also made me nervous. &lt;/p&gt;

&lt;p&gt;Credentials sitting around, no real story for who could run what, no audit trail I could point at if something went sideways. I kept using it for a week and felt worse about it each day.&lt;/p&gt;

&lt;p&gt;I wanted the same speed without the part where I pretend that's fine.&lt;/p&gt;

&lt;p&gt;So I ended up with something I think is pretty cool. I call it querybear. It's a wrapper around my databse to make it AI agent friendly. It adds read-only access, row-level permissions, timeout enforcement, rate limiting, audit trails, schema introspection, and memory with long-living context. &lt;/p&gt;

&lt;p&gt;And it's amazing! I can tell my agent to dive into anything and it can go digging around my data with no risk of misuse.&lt;br&gt;
I know it's a weird pattern but I truly think it's the future. &lt;/p&gt;

&lt;p&gt;Anyone else done similar?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I'm building the future of automated testing</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Fri, 28 Feb 2025 18:55:51 +0000</pubDate>
      <link>https://forem.com/spencerpauly/im-building-the-future-of-automated-testing-2f2d</link>
      <guid>https://forem.com/spencerpauly/im-building-the-future-of-automated-testing-2f2d</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Edit: Thanks to all the early support, I've built and launched my product! You can find it at &lt;a href="https://www.testingbee.io/" rel="noopener noreferrer"&gt;testingbee.io&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Currently, the way to prevent products from breaking is by writing automated tests. These tests define the steps needed to do a task in your product, and run automatically when you deploy changes.&lt;/p&gt;

&lt;p&gt;For example, an automated test that verifies an "Edit profile" form is working might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;allows user to edit profile and save changes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://yourapp.com/profile/edit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="name"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="email"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button:has-text("Save Changes")&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;successMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text=Profile updated successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;successMessage&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&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;Apps can have hundreds or even thousands of these tests and they all get run before every new update is deployed. Awesome!&lt;/p&gt;

&lt;p&gt;But wait... Do you notice something with the test above? What if we update our app and rename the "Save Changes" button? Or add a 3rd input to the edit profile form? Or move the edit profile page elsewhere?&lt;/p&gt;

&lt;p&gt;This is the root problem with automated testing. They will test your functionality, but they're extremely brittle to changes. This makes it difficult to have complete test coverage while also pushing new features as fast as a startup needs to.&lt;/p&gt;

&lt;p&gt;The other problem with automated testing is they are time consuming to write. This is a simple example, but commonly your tests are much more complicated. And again, multiply this work 100 times over.&lt;/p&gt;

&lt;p&gt;Essentially, automated testing code follows an efficiency graph like so:&lt;/p&gt;

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

&lt;p&gt;As you can see, adding more tests increases your confidence that your app works, but also hinders your development speed at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;For most companies – the fact they have to write and maintain automated tests isn't a problem. The value of testing outways the cost towards productivity. That's because typically a new feature is never as valuable as your existing ones.&lt;/p&gt;

&lt;p&gt;But, for startups this typically isn't true.&lt;/p&gt;

&lt;p&gt;A startup exists to solve problems for their customers. A product is the proposed solution. Tests ensure the solution keeps functioning as intended. But here’s the bigger question: what if your product isn’t the right solution to begin with?&lt;/p&gt;

&lt;p&gt;Some argue that you should always test your product rigorously, but I believe testing should come with a purpose. That purpose being to ensure your product keeps solving the problem for your customer.&lt;/p&gt;

&lt;p&gt;If the goal of a test is to ensure your product continues solving the problem, shouldn’t the first priority be validating that your product is solving the problem in the first place?&lt;/p&gt;

&lt;p&gt;Shouldn't you ensure that it’s a viable business before focusing on its technical reliability with testing?&lt;/p&gt;

&lt;p&gt;Most startup founders would agree with me, therefore, you hear this common phrase around the startup world a lot:&lt;/p&gt;

&lt;p&gt;"Move fast and break things" - Mark Zuckerberg&lt;br&gt;
But, I believe we can do even better than this mantra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move fast and don't break things
&lt;/h2&gt;

&lt;p&gt;And that brings us to the solution I've been building for the past month. I built a tool that automatically tests if your product is fully functional, and does it without the overhead of traditional automated tests.&lt;/p&gt;

&lt;p&gt;My tool handles the entire job of automated testing for you, without any micromanagement needed on your part. Instead of writing tests, you simply define broad goals that you want a user to be able to accomplish.&lt;/p&gt;

&lt;p&gt;You don't do this through code, but through simple explanations of end-user experiences. So your testing suite will look something like this:&lt;/p&gt;

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

&lt;p&gt;Through these broad goals – AI will walk through your site and generate the specific tests you need automatically. Essentially writing your entire automated testing suite for you.&lt;/p&gt;

&lt;p&gt;Then, on any code change, we will run those tests against your product to ensure your code is still functioning exactly as it was before.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, what if a test fails?
&lt;/h2&gt;

&lt;p&gt;Unlike traditional tests that only have specific instructions, our approach includes both the specific instructions and a broader goal for each test. This means a test might fail on a specific detail, but still meet the broader goal.&lt;/p&gt;

&lt;p&gt;For example, if the goal is “a user should be able to edit their profile,” deploying a code change that renames the “Save Changes” button to “Save” would cause a specific test to fail. However, from the user’s perspective, this product is still functioning perfectly.&lt;/p&gt;

&lt;p&gt;And truly, this test shouldn't fail. You want your tests to ensure that your product is functional. But, in the real world tests almost always fail from a product change that doesn't break the user experience.&lt;/p&gt;

&lt;p&gt;Here’s where we shine: we can determine if your product is broken or if it's just a code change that means you need to update your test. And if it's the latter, we'll heal your test automatically with just the press of a button.&lt;/p&gt;

&lt;p&gt;So, for the example above, we'll update the specific instructions to check for a "Save" button instead of a "Save changes" button, re-run the test, then save it to be updated moving forwards.&lt;/p&gt;

&lt;p&gt;No more pushing code changes simply to update your testing code.&lt;/p&gt;

&lt;p&gt;Another advantage of this is that we remove the false alerts that you would otherwise get frequently. Since we can identify when a test is a product breakage and not just a product change, those high priority alerts mean something!&lt;/p&gt;

&lt;p&gt;I'll be launching soon, there's still functionality to add but I have the core working and I'm excited to share it!&lt;/p&gt;

&lt;p&gt;Anyways that's all, thanks!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>testing</category>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why does testing suck so much in 2025?</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Fri, 21 Feb 2025 18:19:07 +0000</pubDate>
      <link>https://forem.com/spencerpauly/why-does-testing-suck-so-much-1i2e</link>
      <guid>https://forem.com/spencerpauly/why-does-testing-suck-so-much-1i2e</guid>
      <description>&lt;p&gt;&lt;em&gt;Why are tests so time consuming to write?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And why do they break so easily?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And why do they offer no guidance on what went wrong when they do break?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This past month I evaluated some of the most common end-to-end (E2E) testing frameworks: Cypress, Playwright, Selenium — and none of them offered a solution to these problems.&lt;/p&gt;




&lt;p&gt;My solution would be something like this: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write automated tests from an end user's perspective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is an example of what your test would look like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Click the searchbar"&lt;/li&gt;
&lt;li&gt;Type "Docs site"&lt;/li&gt;
&lt;li&gt;Hit enter&lt;/li&gt;
&lt;li&gt;You should now be on "docs.ourapp.com"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Take these commands and let AI execute them as a human would.&lt;/p&gt;

&lt;p&gt;It fixes all the problems above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time consuming to write?&lt;/strong&gt;&lt;br&gt;
Not anymore. Just write the steps in pure english.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Break easily?&lt;/strong&gt; &lt;br&gt;
 Not anymore. Because if the end user flow keeps working then the test will keep working even if the underlying code changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No guidance to fix tests?&lt;/strong&gt;&lt;br&gt;
Get a direct printout from the AI saying exactly which step failed and &lt;strong&gt;why&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Edit: Thanks to early demand I've built this product! Find it at &lt;a href="//testingbee.io"&gt;testingbee.io&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>programming</category>
      <category>playwright</category>
      <category>selenium</category>
    </item>
    <item>
      <title>I built an AI Tool to write medium posts 10x faster.</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Wed, 06 Jul 2022 15:52:06 +0000</pubDate>
      <link>https://forem.com/spencerpauly/i-built-an-ai-tool-to-write-medium-posts-10x-faster-3b5i</link>
      <guid>https://forem.com/spencerpauly/i-built-an-ai-tool-to-write-medium-posts-10x-faster-3b5i</guid>
      <description>&lt;p&gt;In 2020, I fell in love with blogging here on Medium. Articles are fun to write, provide value for others, and even make a little money. It's a perfect combination!&lt;/p&gt;

&lt;p&gt;But, there's one really, really annoying issue with writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's. So. Time-consuming.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even a simple post like this one takes me 4 or 5 hours to write. This heavily limits my output. If I'm going to write a new post, I have to mentally commit to giving up a day of my life to do it. And that shouldn't be the case.&lt;/p&gt;

&lt;p&gt;So, I decided to analyze how I spend my time while crafting a new article. This was the breakdown.&lt;/p&gt;

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

&lt;p&gt;The most shocking finding: I spend 50% of my time editing.&lt;/p&gt;

&lt;p&gt;But, thinking back, that makes sense. I have many unpublished rough drafts that I simply haven't finished because of the time commitment of editing. So, I set out to solve this problem.&lt;/p&gt;

&lt;p&gt;I found some tools that would help me write faster, but they usually added another layer of workflow complexity. Either I'd need to write in a completely separate editor, or get only half the functionality I wanted.&lt;/p&gt;

&lt;p&gt;So, I decided to set out and build my own tool to write medium posts fast.&lt;/p&gt;

&lt;p&gt;Introducing, my AI writing tool for medium.&lt;/p&gt;

&lt;p&gt;I'll note, this was just an experiment. I made a local version to test, but after finding how much time it's saved me I thought it would be cool to share.&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;/p&gt;

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

&lt;p&gt;This general gist is that the tool combines AI and traditional grammar-checking to make editing a breeze. Idea generation can be done on-the-fly as the AI creates sentence suggestions. Trimming down long, confusing, or badly worded sentences is easy as-well because the suggestions are available right in the medium editor.&lt;/p&gt;

&lt;p&gt;Plus, it's just a chrome extension. Everything is still done in the medium editor so my workflow isn't compromised.&lt;/p&gt;

&lt;p&gt;Here's a taste of some of the functionality I found to be most useful:&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 AI Brainstorming - Title &amp;amp; subtitle suggestions using AI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyow1p0l7wq3ggqkqtmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyow1p0l7wq3ggqkqtmf.png" alt="AI-powered title and subtitle brainstorming for medium articles" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is huge. The AI hooks into a database of millions of blog posts to give title suggestions based on patterns seen elsewhere. Since I usually don't go with my first title, this feature makes brainstorming easy.&lt;/p&gt;

&lt;p&gt;Plus, the AI uses the content of your post to guide its suggestions. As I add more content to a post, I get new and different title ideas that I might not've thought of before.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Grammar checking - directly in the medium editor
&lt;/h3&gt;

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

&lt;p&gt;Usually this is the most time-consuming part of writing. It's hard to write perfect sentences the first time, so a grammar checking tool is an absolute must for me.&lt;/p&gt;

&lt;p&gt;Usually, I offload this work to another tool. But copying the content back and forth can become a pain. I added this functionality to my tool so it can all be done on Medium's editor. No more time-wasting.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Sentence suggestions - rewrite &amp;amp; brainstorm with AI
&lt;/h3&gt;

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

&lt;p&gt;This is one of my favorite features. As I write, the AI will offer suggestions for ways to rewrite a sentence or continue a train of thought. I don't always use these suggestions, but they keep me thinking about how to flow my thoughts together and I find that &lt;em&gt;invaluable&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I built this tool as a simple local chrome extension for myself. I've thought of providing it publicly, but it would be a lot of work to take it over the finish line.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is this something people would be interested in?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Like I said, it would take a lot of effort to deliver it publicly, but if this is something people would use then I might give it a shot. I've even thought of ideas to make it more powerful.&lt;/p&gt;

&lt;p&gt;Things like hooking into other tools to generate images on-demand. But again, I mostly built it to work for my use-case so I'd be interested to hear how others would find this helpful.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>ai</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Users preferred the less straightforward UX – and I finally understand why</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Wed, 22 Jun 2022 23:50:32 +0000</pubDate>
      <link>https://forem.com/spencerpauly/users-preferred-the-less-straightforward-ux-and-i-finally-understand-why-2lf6</link>
      <guid>https://forem.com/spencerpauly/users-preferred-the-less-straightforward-ux-and-i-finally-understand-why-2lf6</guid>
      <description>&lt;p&gt;Two years ago, I learned a valuable lesson about creating good UX:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It might not seem intuitive, but sometimes users prefer the less straightforward UX&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this time, I was building the first version of a new cross-platform app called &lt;a href="https://skiwise-app.com" rel="noopener noreferrer"&gt;Skiwise&lt;/a&gt;. I thought I was creating the best experience possible, but as I later learned, straightforward doesn't always equal intuitive.&lt;/p&gt;

&lt;p&gt;This is the story of how I learned this lesson, and how these learnings can help you build better software.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's confusing?
&lt;/h2&gt;

&lt;p&gt;Skiwise is an app that lets cross-country skiers access crowd-sourced reports on the trail conditions of various ski trails. This lets them decide where to ski on a given day and what skis/wax/clothes to bring with them. You can think of this as essentially "the weather app for cross-country ski trails".&lt;/p&gt;

&lt;p&gt;With the goal clear, the initial version of the UI looked something like this:&lt;/p&gt;

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

&lt;p&gt;As you can see, the main page contains a list of trails you follow and displays the most recent trail report from each trail. "This is great", I thought at the time, "The info is instantaneous! You can browse the newest trail reports in 2 seconds! There's no friction! People will love this!".&lt;/p&gt;

&lt;p&gt;And the result? People didn't love it.&lt;/p&gt;

&lt;p&gt;So, I went back to the basics. And there's nothing more basic than watching users interact with your app. But, it wasn't until I put the app in the hands of my Mother that I discovered the problem.&lt;/p&gt;

&lt;p&gt;She loaded the app, got to the home screen, scrolled a bit, stopped, scrolled some more, stopped again, then looked at me and said "what now?".&lt;/p&gt;

&lt;p&gt;And that's when I had the "aha moment".&lt;/p&gt;

&lt;p&gt;See, I'd made the information so readily available that it left the user no desire to dive deeper. It took away all the exploration. It's like being handed a solved Rubix cube. There's no clear direction, no problem to solve, and no task to be accomplished.&lt;/p&gt;

&lt;p&gt;And, the way this information was presented didn't line up with a user's mental model. It was hard for people to conceptualize that the feed was showing the most recent report for favorite trails in order of report date.&lt;/p&gt;

&lt;p&gt;This is similar to having a list of the most popular book by each artist sorted by the book's release date. It's just a complicated set of relationships to think about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplifying things, by adding complexity
&lt;/h2&gt;

&lt;p&gt;So, I changed the user experience. Instead of delivering all the information on the home screen, users now had to hunt on a map for it. And this dramatically changed the experience.&lt;/p&gt;

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

&lt;p&gt;Now, instead of the info being discoverable instantly, it takes about 30 seconds. But, it lines up better with a user's mental model. When surveyed, 76% of users reported that they only skied at trails within 30 minutes of their home. This was a huge breakthrough.&lt;/p&gt;

&lt;p&gt;It indicates that people place the highest priority on nearby trails, and don't care about trails far away from home. This points to a clear data structure – a map.&lt;/p&gt;

&lt;p&gt;And, there's a certain satisfaction when you click on a map, find a trail, see a recent trail report, and get your answers.&lt;/p&gt;

&lt;p&gt;So, despite it taking objectively longer for users to get their answers, they loved it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How you can apply this?
&lt;/h2&gt;

&lt;p&gt;The key is in mental models. If you think about it, every app comes with a set of mental models and interaction patterns that users will intuitively follow.&lt;/p&gt;

&lt;p&gt;For example, when you use Instagram you quickly learn that posts are attributed to users, with no exceptions. This becomes a core mental model of the app. It helps everything else become intuitive as well. You learn that comments are attributed to users. And posts can be clicked on to see a user's profile. And your feed is just a series of posts.&lt;/p&gt;

&lt;p&gt;So, say you have a software-as-a-service app. Write down the core mental models your users are using and use that to determine if your UI is intuitive. Does a user own multiple projects in their dashboard? Do settings belong to projects or users? Where should the settings button be located to indicate that?&lt;/p&gt;

&lt;p&gt;From there, use something like &lt;a href="https://hotjar.com" rel="noopener noreferrer"&gt;Hotjar&lt;/a&gt; or &lt;a href="https://clarity.microsoft.com" rel="noopener noreferrer"&gt;Microsoft Clarity&lt;/a&gt; to watch your users interacting with your app. Do they see the mental models the same way you do?&lt;/p&gt;

&lt;p&gt;Want some more tips? I wrote another article with quick fixes for &lt;a href="https://blog.pwego.com/7-common-saas-dashboard-mistakes-how-to-fix/" rel="noopener noreferrer"&gt;7 common SaaS dashboard mistakes&lt;/a&gt;. These can give you good hints on low hanging fruit that might be causing friction for users of your app.&lt;/p&gt;

&lt;p&gt;Also, feel free to get in contact with me directly. I run a consultancy called &lt;a href="https://pwego.com" rel="noopener noreferrer"&gt;Pwego&lt;/a&gt; where I help businesses write better software and create measurable business outcomes as a result. If this is a pain point for your business, let's see if I can help!&lt;/p&gt;

</description>
      <category>ux</category>
      <category>design</category>
      <category>startup</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>The #1 Best Design Pattern for Managing Forms in React</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Fri, 12 Nov 2021 19:47:13 +0000</pubDate>
      <link>https://forem.com/spencerpauly/the-1-best-design-pattern-for-managing-forms-in-react-4215</link>
      <guid>https://forem.com/spencerpauly/the-1-best-design-pattern-for-managing-forms-in-react-4215</guid>
      <description>&lt;p&gt;Ughh… why does form code in React always get so messy?&lt;/p&gt;

&lt;p&gt;It starts out simple: a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; component, a couple input fields, and a submit button. But soon things get a little more complicated.&lt;/p&gt;

&lt;p&gt;You think, "hmmm.. I want some more validation for this zip code field". So you add a custom workaround that validates the data in the input field.&lt;/p&gt;

&lt;p&gt;Then, you think "I want to disable the submit button when the form is submitting". So you create another custom workaround that keeps track of what's submitting, and when things are complete, etc.&lt;/p&gt;

&lt;p&gt;Then, you think "I want better error handling". So you add yet another workaround.&lt;/p&gt;

&lt;p&gt;And over time that simple form balloons into a 400-line long super-component with multiple useEffects, useStates, and custom logic to handle all the edge cases.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;I've had this trouble more times than I'd like to admit. So 6 months ago, I decided to double down and find the solution. I wanted to know:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What's the absolute BEST way to manage forms in React so they're organized, performant, and easy to debug?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's what I'm going to share here today.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Form Library - Do I need one?
&lt;/h1&gt;

&lt;p&gt;I've come at this crossroads before. As a project is small the answer usually starts as "&lt;strong&gt;nah&lt;/strong&gt;", then over time it inevitably sways towards "&lt;strong&gt;please, please yes&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;So now, I advocate for form management libraries no matter what scale of project. Form libraries usually have a relatively small bundle size and make a world of difference for code organization.&lt;/p&gt;

&lt;p&gt;But, I should note: I've also seen custom form management work in the past.&lt;/p&gt;

&lt;p&gt;The issue is that it's really difficult. It's possible, but even if you're successful you'll usually end up building a similar version of another form library except without all the great documentation.&lt;/p&gt;

&lt;p&gt;That's why I recommend starting your project with a good form library from the get-go. So that brings us to the next question.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's the best form library?
&lt;/h1&gt;

&lt;p&gt;This decision making process could be a whole other article in itself. But, I want to focus on concrete design patterns today, so I'm only going to give a high-level overview of the landscape.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Plethora of Form Management Libraries
&lt;/h4&gt;

&lt;p&gt;The landscape for form management libraries in React is huge. But, luckily it's concentrated among only a few popular libraries. Some of the most popular are: react-hook-form, formik, redux form, and react-final-form.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of their popularity, with Formik as the most popular and react-hook-form chasing close on their heals.&lt;/p&gt;

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

&lt;p&gt;As I already mentioned, I'm not going to be deeply comparing these solutions in this article. But, if you want a great article comparing these, &lt;a href="https://dev.tocheck%20out%20this%20great%20post%20comparing%20these%20libraries%20from%20Retool"&gt;https://retool.com/blog/choosing-a-react-form-library/&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;With that said, the two form libraries that I consider to be an excellent choice are &lt;em&gt;Formik&lt;/em&gt; and &lt;em&gt;React-Hook-Form&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Both provide hook-centric form management and have great documentation, active devs, and a healthy user base.&lt;/p&gt;

&lt;p&gt;However, between these two, I tend to lean towards React-Hook-Form and I'll explain why below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why React-Hook-Form?
&lt;/h3&gt;

&lt;p&gt;React-hook-form (RHF) is great because it prioritizes hooks to manage your form state (hence the name). This makes it fast, flexible, and a breeze to work with if you're already using hooks.&lt;/p&gt;

&lt;p&gt;Among it's various benefits, one advantage over Formik is that react-hook-form was created exclusively for hooks. This means, although react-hook-form can't support class components, their docs and best practices are more focused. If you look up articles online, you won't find a lot of outdated guides with old design patterns. I find this extremely valuable when trying to learn a new library.&lt;/p&gt;

&lt;p&gt;They also have numerous other small performance, bundle, and flexibility advantages over the other libraries. Here's just some examples:&lt;/p&gt;

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

&lt;p&gt;That's why I chose React-Hook-Form. However, if your codebase uses a lot of class components you might be better off going with Formik as it'll be easier to integrate into your components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm going to touch on more advanced design patterns in this article, however if you're confused at any time here's some great resources for understanding React-Hook-Form: &lt;a href="https://react-hook-form.com/get-started" rel="noopener noreferrer"&gt;The official getting started guide&lt;/a&gt;, &lt;a href="https://blog.logrocket.com/using-material-ui-with-react-hook-form/" rel="noopener noreferrer"&gt;Using RHF with material UI&lt;/a&gt;, and &lt;a href="https://travis.media/react-hook-form-controller-examples/" rel="noopener noreferrer"&gt;RHF with 5 different UI library examples&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The 3 Layer Approach
&lt;/h1&gt;

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

&lt;p&gt;The basic premise of the 3 layer approach is to take a complicated form component and split it into three parts.&lt;/p&gt;

&lt;p&gt;Each part will be its own react component and will focus on one responsibility of the form (see: SOLID). Each part will also be named with a suffix (Apollo, Logic or View), which will make it easier to find.&lt;/p&gt;

&lt;p&gt;Here's an overview of what each component does:&lt;/p&gt;

&lt;h4&gt;
  
  
  Apollo Component
&lt;/h4&gt;

&lt;p&gt;This component handles strictly the network requests for your form (aka. fetching the initial data for the form, and submitting the final data to your backend). It's named "Apollo" because I typically use Apollo to talk to my GraphQL backend. Feel free to use a more relevant suffix such as: "API", "Network", or "Fetch" if you prefer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Logic Component
&lt;/h4&gt;

&lt;p&gt;This handles the logic for the form. This is the component where you'll define the shape of the form, default values, and validation.&lt;/p&gt;

&lt;h4&gt;
  
  
  View Component
&lt;/h4&gt;

&lt;p&gt;This component renders the view of the form. It's meant to be a stateless component. However, I usually allow view-related state in this component such as an isOpen toggle for an expandable section of the form or something similar.&lt;/p&gt;

&lt;h1&gt;
  
  
  The 3 Layer Pattern Further Explained
&lt;/h1&gt;

&lt;p&gt;This chart shows how the data will flow between these three layers to create an organized form structure. Start at the Apollo.tsx file and follow the arrows to read how the data will flow through the components.&lt;/p&gt;

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

&lt;p&gt;Let's dive a little further into each of these components. I use TypeScript in this example, because it will help give a good look into the different types of data being passed around.&lt;/p&gt;

&lt;p&gt;Also, &lt;a href="https://codesandbox.io/s/react-hook-form-3-layer-design-pattern-d4rup?from-embed" rel="noopener noreferrer"&gt;here is the finished codebase&lt;/a&gt;. If you're a hands-on learner feel free to play around yourself as you read.&lt;/p&gt;

&lt;h2&gt;
  
  
  CreateUserApollo.tsx Explained
&lt;/h2&gt;

&lt;p&gt;The Apollo component is responsible for fetching form data over the wire. Here's what it looks like.&lt;/p&gt;


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


&lt;p&gt;There's a couple things I want to point out about this component.&lt;/p&gt;

&lt;p&gt;First of all, notice how the data fetched from the database is transformed before being passed down into the default values of . This is important, because in general it's a good idea not to trust data fetched from over the wire. If you don't do this it can go wrong in one of three ways.&lt;/p&gt;

&lt;p&gt;(a) You can end up fetching too many fields from the API. This means your form will have more defaults than it needs. This can add clutter to your form and problems when we get to validation.&lt;/p&gt;

&lt;p&gt;(b) This also safeguards against bad defaults (ex. undefined). Instead of trusting the backend, it's a good idea to provide sensible defaults, such as the empty string, just in-case.&lt;/p&gt;

&lt;p&gt;(c) It's more robust. Notice how the user field from the API is transformed into the username field before being passed down to the form? This is useful for other fields too. Ex. parsing a string timestamp from the backend into a Date object for the form.&lt;/p&gt;

&lt;p&gt;The second thing I want to point out is regarding the handleSubmit function. This function takes the submitted form data, transforms it into JSON for the API, and returns an async function for updating the database with the result.&lt;/p&gt;

&lt;p&gt;Returning the async function is important. You'll see this a bit later, but essentially it allows you to await the API response in your CreateUserLogic component which means you can know what the submission status of the form currently is.&lt;/p&gt;

&lt;h2&gt;
  
  
  CreateUserLogic.tsx Explained
&lt;/h2&gt;

&lt;p&gt;The goal of this component is simple: set up the form with the default values, pass the form down to the view layer, then handle submitting the form to the parent component when the submit button is pressed.&lt;/p&gt;


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


&lt;p&gt;The main thing I want to point out here is the handleSubmit function. You'll remember that the Apollo component had a handleSubmit function too. Why do you need two of them?&lt;/p&gt;

&lt;p&gt;The reason is to keep our three layers modular. The handleSubmit in this component lets you make state changes after a successful submission of the form. It doesn't care how that data is submitted, it just cares about when it completes.&lt;/p&gt;

&lt;p&gt;Trust me, I've tried doing it other ways and eventually you'll realize this way is the cleanest. It lets you keep each layer from needing to care about what's happening in the other layers and instead simply focusing on what they care about.&lt;/p&gt;

&lt;p&gt;In this example, we reset the form after submitting. But, you can just as easily use this to route to a different page, show a success toast, close a modal, etc. This design pattern leaves it up in the air, which is good.&lt;/p&gt;

&lt;p&gt;Also, it's important that you either await or return the onSubmit(data) function. If you don't, everything will still work but react-hook-form won't know when you've completed the submission process and won't properly handle the isSubmitting state of the form.&lt;/p&gt;

&lt;h2&gt;
  
  
  CreateUserView.tsx Explained
&lt;/h2&gt;

&lt;p&gt;Finally we have the simplest component. This one simply renders out your form fields. Since you've done all the hard work in the layers above this component can be pretty simple.&lt;/p&gt;

&lt;p&gt;This is great because in a large form this will usually be your biggest component. Additionally, this component only handles the "look" of the form and won't deal with any logic. This is great because now you can easily hand this file off to a designer and the designer won't need to care about how the form works, they only have to worry about how it &lt;em&gt;looks&lt;/em&gt;. Which is great!&lt;/p&gt;


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


&lt;h1&gt;
  
  
  The benefits of this pattern
&lt;/h1&gt;

&lt;p&gt;Ok, so I mentioned at the beginning of the article all my pain points when building forms. Not only does this structure solve all of those, it also has some other inherit benefits as-well.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ Built in type checking and validation for every step of your form
&lt;/h4&gt;

&lt;p&gt;If you noticed, the logic component contains per-field validation, and every step of this process has strong typescript typings. This makes it very hard to mess up and much easier to debug.&lt;/p&gt;

&lt;h4&gt;
  
  
  🔍 Easy to find where things happens
&lt;/h4&gt;

&lt;p&gt;Do you have an issue submitting data to the backend? It's likely in the Apollo component. Issue with the default value of a field? Logic component. Issue with the "look" your form? View component. Super easy!&lt;/p&gt;

&lt;h4&gt;
  
  
  💨 Automated testing is a breeze
&lt;/h4&gt;

&lt;p&gt;This is a commonly under-looked benefit of this pattern. But, if you notice, you can test the functionality of a form by passing props to the Logic components directly. There is no need to mock your backend at all since you can test all the functionality by bypassing the Apollo component entirely.&lt;/p&gt;

&lt;h4&gt;
  
  
  🎁 Forms become much more composable
&lt;/h4&gt;

&lt;p&gt;This means you can mix and match different layers to have the form behave differently. You can have different Apollo components submit form data in a different way (ex. editing vs. creating a document). Or vice versa, you can reuse an Apollo component for different forms to submit different data to the same backend services. Really cool!&lt;/p&gt;

&lt;h4&gt;
  
  
  👥 Easy to Divide-And-Conquer for Teams
&lt;/h4&gt;

&lt;p&gt;This structure lends itself well to working with a team. Your designer can work on the View layer, while the backend person can work on the Apollo component. Then, you can easily meet in the middle at the Logic component and get your new feature launched twice as fast!&lt;/p&gt;

&lt;h1&gt;
  
  
  And that's the design pattern!
&lt;/h1&gt;

&lt;p&gt;As you can see, by combining a good form library with a good design pattern can make messy form code a thing of the past. It allows for easier collaboration, cleaner development, and faster debugging. What's not to like?&lt;/p&gt;

&lt;p&gt;If you have any further questions or improvements, leave a comment!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Here's Actually Why Deno Flopped</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Mon, 28 Sep 2020 13:54:15 +0000</pubDate>
      <link>https://forem.com/spencerpauly/here-s-actually-why-deno-flopped-3k1a</link>
      <guid>https://forem.com/spencerpauly/here-s-actually-why-deno-flopped-3k1a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Brought to you by &lt;a href="https://engine.so" rel="noopener noreferrer"&gt;engine.so&lt;/a&gt; - a tool to instantly create a public self-service knowledge base for your customers with Notion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deno is a Javascript / TypeScript runtime looking to take the place of Node.js as the status quo. It boasts a wide slew of features and has a lot of hype around the project with almost 68,000 stars on Github:&lt;/p&gt;

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

&lt;p&gt;With so many great features, the question to ask is:&lt;br&gt;
Why didn't Deno take off when it released it's official version 1.0?&lt;/p&gt;

&lt;p&gt;This article looks to dive into that question…&lt;/p&gt;




&lt;h1&gt;
  
  
  So, what's Deno?
&lt;/h1&gt;

&lt;p&gt;Deno is a secure JavaScript and TypeScript runtime created by Ryan Dahl (who's also the original creator of Node.js). It was created to fix some of the oversights made when first designing Node.js back in 2009. In my opinion this motivation makes a lot of sense because I'm sure every programmer would love to get a chance to rewrite their 10 year old code.&lt;br&gt;
In this case, Deno boasts quite a few features over Node.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deno is secure by default. Access to the file system, network, or environment has to be opt-in&lt;/li&gt;
&lt;li&gt;Deno was built for TypeScript out of the box
External files are explicitly referenced by a URL. No package.json.&lt;/li&gt;
&lt;li&gt;Import statements include file extensions (.ts,.tsx,.js,.json)&lt;/li&gt;
&lt;li&gt;Built-in dependency inspector and file formatter utilities
And more…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with these features in its arsenal combined with an enormous amount of developer hype, Deno had its official 1.0 release in May 2020.&lt;/p&gt;

&lt;p&gt;And then…&lt;/p&gt;

&lt;p&gt;Crickets.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Didn't Deno Take Off?
&lt;/h1&gt;

&lt;p&gt;Deno looked like it had all the ingredients for success. It had a massive following, a solid batch of features, an experienced creator, and more, but it didn't really have the growth everyone expected. Why is that?&lt;/p&gt;

&lt;p&gt;I think it's best to look at it from a business perspective. See, most of us forget that building open source software is really no different than building software for users. The standard economic principles of supply and demand still play a large role.&lt;/p&gt;

&lt;p&gt;When someone is creating a new open source project, they're typically going to be competing with something that already exists. With that in mind, you have to consider not only how good your new project is, but also what it looks like compared to what's already available.&lt;/p&gt;

&lt;p&gt;In Deno's case, what was already available was Node.js, and while Node.js might have its flaws, it's still very capable of doing its job. Now, if Deno came out with a blowaway feature that Node.js would never be able to replicate, that might change the game. But it didn't.&lt;/p&gt;

&lt;p&gt;Deno only really sported "minor features" from a users perspective. It had a cleaner codebase, used up-to-date best-practices, and had better security, but those things are really only "features" to a user, not a product in themselves. You could make an email client exactly like Gmail except it has better security and a 50% speed improvement, but users still wouldn't switch to it because even the tiny amount of time it takes to create a new bookmark wouldn't be worth it.&lt;/p&gt;

&lt;p&gt;So that's strike 1 against Deno: It has quite a few nice-to-have features, but there's nothing standout that inspires users to switch away from Node.js.&lt;/p&gt;

&lt;p&gt;The other major strike against Deno is that it doesn't support NPM packages. If Deno were able to support NPM packages, that would change the game for them. Deno supporting NPM packages would make them much less of a "separate email client", and more like a better wrapper around the current client.&lt;/p&gt;

&lt;p&gt;Supporting NPM packages would greatly reduce the barrier to entry. It would act as a good stepping stone for users to migrate their projects and libraries towards Deno.&lt;/p&gt;

&lt;p&gt;Think of it as similar to TypeScript's "strict-mode". For users with a huge codebase of JavaScript, jumping directly into TypeScript would cripple your productivity for weeks while you sort through all the error messages. Because TypeScript has the ability to disable strict mode, it can act as a stepping stone for users to slowly migrate over to pure TypeScript. This gives them a much lower barrier to entry, and in turn has helped TypeScript rip away market share from JavaScript in recent years.&lt;/p&gt;




&lt;h1&gt;
  
  
  What's the Takeaway?
&lt;/h1&gt;

&lt;p&gt;I think this an interesting case-study that exemplifies a larger methodology in business. The takeaway is that if you're going to release a new product into the market, you have to make sure it's something where the upside is so great that it overcomes the resistance from people switching from the status quo.&lt;/p&gt;

&lt;p&gt;In Deno's case they had the initial allure, but when it came down to it Deno was really only offering a collection of small "fixes" at the price of losing the whole NPM ecosystem that Node.js had cultivated and this tipped the scales for them.&lt;/p&gt;




&lt;h1&gt;
  
  
  Where does Deno go from here?
&lt;/h1&gt;

&lt;p&gt;Well they have a decision to make. They can either work on adding backwards compatibility to Node.js libraries, or they can increase their offering to make the compulsion to switch just that much more enticing. I personally think backwards compatibility is the way to go, and I think if that was added it would drastically alter the future of the project.&lt;/p&gt;




&lt;p&gt;Either way, best of luck to the deno team and I hope the best technology wins in the end. I hope you enjoyed the article, thanks.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>deno</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Here's A Simpler Alternative to Redux</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Fri, 11 Sep 2020 21:51:11 +0000</pubDate>
      <link>https://forem.com/spencerpauly/state-containers-a-simpler-alternative-to-redux-for-state-management-3i93</link>
      <guid>https://forem.com/spencerpauly/state-containers-a-simpler-alternative-to-redux-for-state-management-3i93</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Brought to you by &lt;a href="https://engine.so" rel="noopener noreferrer"&gt;engine.so&lt;/a&gt; - a tool to instantly create a public self-service knowledge base for your customers with Notion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;The "Container" pattern is a concept introduced in the Unstated-Next library. The pattern thinks about state as a variety of "Containers" that hold a modular slice of the global application state. To provide this state you create a Context across your application, then you can access it through hooks.&lt;/p&gt;

&lt;p&gt;Compared to something like Redux, this Container pattern offers a hook-centric way to manage state. It's easier to learn, scales well with your application, and provides an intuitive way to think about global state. Here's how it works.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is the Container Pattern?
&lt;/h1&gt;

&lt;p&gt;The container pattern is a methodology where instead of having all your global state in one external library or "global store" such as Redux, you divide that state into multiple chunks called "Containers". These chunks are responsible for managing their own state and can be pulled into any functional component in the app by using something similar to the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const {user} = Auth.useContainer();&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This pattern works really well because it divides state up into self-managing chunks rather than having everything intertwined. Each component can simple pull in the chunk of state that it wants to use and is only dependent on a part of your applications state.&lt;/p&gt;

&lt;p&gt;Each chunk of state is really easy to reason about. It's simply a custom hook wired up to a context provider. That's it. The term "Containers" is really just a wrapper term to mean "a React Custom Hook + a Context Provider", so when someone is recommending state management with hooks + useContext, they're technically recommending this container pattern.&lt;/p&gt;

&lt;p&gt;To use containers you just have to import the Context and use the hook. You don't technically need any external libraries, however I use a library called Unstated-Next because it gives me some benefits that make this pattern even easier.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is Unstated-Next?
&lt;/h1&gt;

&lt;p&gt;Unstated-Next is a tiny library that helps us reason about these global containers a little bit easier. This library is tiny (like 200 bytes tiny), and it's for good reason because it basically doesn't do anything on top of what React's Context API already does.&lt;/p&gt;

&lt;p&gt;This library is 100% optional for this design pattern. It just provides small API improvements that make Context easier to work with. Some of the main benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type-Checking:&lt;/strong&gt; It gives you typescript support out of the box. This was one of my gripes with using the React Context API, so it's nice to see that unstated-next solves that issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Handling:&lt;/strong&gt; If you try to access a container that doesn't have a Context provider above it in the React DOM tree, it will throw an error. This is a life-saver for debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier to Think About:&lt;/strong&gt; Thinking about contexts can seem abstract at times, but using this library with the mental concept of "containers" is a lot easier to reason about.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What does this pattern look like?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  File Structure
&lt;/h2&gt;

&lt;p&gt;When I use this pattern, I put all my containers in a "container" folder at the root of the src directory.&lt;/p&gt;

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

&lt;p&gt;I suffix each container with the word "Container" and have all the relevant code for a container all colocated in one file.&lt;/p&gt;

&lt;p&gt;This already has benefits over something like Redux, where a single responsibility might be divided over 3 or 4 files for the actions, reducer, store, selectors etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Container File
&lt;/h2&gt;

&lt;p&gt;The container is where your slice of state will live. This file contains everything necessary for reading and writing to this part of state. Here's what a container file may look like for an AuthContainer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The reducer. This would be very similar to your reducer in Redux.
// This is optional, you can just use useState instead, but this is
// here to show that if you want to use a reducer and do more
// complicated state transitions you can.
function authReducer(state: AuthState, action: Action) {
   ...
}
// Custom Hook
function useAuth(initialState: AuthState) {
   const [state, dispatch] = useReducer(authReducer, initialState);
const loginWithGoogle = () =&amp;gt; {
      dispatch(loggingIn());
      doGoogleLogin()
         .then(user =&amp;gt; dispatch(success(user)))
         .catch(err =&amp;gt; dispatch(error(err.message)));
   }
const loginWithEmailPassword = (email, password) =&amp;gt; {
      dispatch(loggingIn());
      doEmailPasswordLogin(email, password)
         .then(user =&amp;gt; dispatch(success(user)))
         .catch(err =&amp;gt; dispatch(error(err.message)));
   }
const logout = () =&amp;gt; dispatch(logout());
return { 
      user: state.data,
      isAuthenticating: state.loading,
      error: state.error,
      loginWithGoogle,
      loginWithEmailPassword,
      logout
   };
}
// Create the Container (this can be a Context too)
// You just pass in the custom hook that you want to build the
// container for.
export const Auth = createContainer(useAuth);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is really clean because it's basically just a custom hook and then that little line at the bottom to make it a container. When you add that container code at the bottom, it makes this custom hook have the same state even if used in multiple different components. This is because the Unstated-Next containers just use the Context API under the hood.&lt;/p&gt;

&lt;p&gt;To make that work you first need to add a Store to your application which will store all the containers. This might look something like this:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Side-Note: I think there could be a better way to manage a Store like this. If there were a way to dynamically create this structure based on an array of containers or something like that, I think that would be a lot cleaner.&lt;br&gt;
Also if there was a way to make all these load at the same level of the DOM so any container can access any other container that would be amazing too, but sadly I think that's a limitation with React.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll want to slot this in the root component so your root component looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const App: React.FC = () =&amp;gt; {
   return (
      &amp;lt;Store&amp;gt;
         &amp;lt;ReactRouter&amp;gt;
            &amp;lt;AppRoutes&amp;gt;
         &amp;lt;/ReactRouter&amp;gt;
      &amp;lt;/Store&amp;gt;
   );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! If you did this correctly, you should now be able to go into any of your React components and use this hook like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const LoginPage: React.FC = () =&amp;gt; {
   ...
   const {
      formLogin, 
      googleLogin, 
      isAuthenticating,
      user
   } = Auth.useContainer();
   useEffect(() =&amp;gt; {
      if (user) {
         history.push('/home');
      }
   }, [user]);
   ...
   return (
      &amp;lt;div&amp;gt;
         &amp;lt;button onClick={() =&amp;gt; googleLogin()}&amp;gt;
            Login with Google
         &amp;lt;/button&amp;gt;
         ...
      &amp;lt;/div&amp;gt;
   );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you did everything correct, following this pattern should work for you! If you did something wrong Unstated-Next might throw an error that says that the container's provider hasn't been created, but that's good because it's an explicit error message for a bug that can be really difficult to track down if you're using the basic React Context.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Not Use Redux?
&lt;/h1&gt;

&lt;p&gt;Redux is great for state management at a large scale. It's the tried-and-tested way to manage state for large applications. However, for the vast majority of applications out there, Redux is the wrong place to start. It's very boilerplate heavy and likely isn't going to give you many benefits unless you already know your use-case demands it.&lt;/p&gt;

&lt;p&gt;Therefore I'm offering this pattern as an alternative.&lt;/p&gt;

&lt;p&gt;The main benefit you get from this pattern is that it makes more sense from a developer's perspective. Redux takes all your state and pulls it away from the view layer. I'd argue that a better way to manage state would be to colocate it with the view layer that uses it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is why React Hooks exist.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can already see things moving towards this methodology with the movement of other pieces of state out of things like Redux and into hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local state&lt;/strong&gt; =&amp;gt; useState / useReducer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API state&lt;/strong&gt; =&amp;gt; React-Query / useSWR / Apollo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form state&lt;/strong&gt; =&amp;gt; React Hook Form / Formik&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, it makes sense that the global state also be built to fit well into a hook ecosystem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since a majority of my state management is done by various hook libraries, it makes sense that my global state management also be hook-centric.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The container pattern implements this idea. It offers the majority of the functionality as Redux at a fraction of the time-cost and is designed with hook-centric development at the forefront.&lt;/p&gt;

&lt;p&gt;For any small-medium sized-project, this pattern is a no-brainer for me. For a larger project, it depends on the use-case.&lt;/p&gt;

&lt;p&gt;Here's some comparisons between the container pattern and Redux:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Container pattern has the following benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less boilerplate than something like Redux.&lt;/li&gt;
&lt;li&gt;Uses the native Context API under the hood.&lt;/li&gt;
&lt;li&gt;You can learn the API in 10 minutes if you know useState, useContext and Custom Hooks.&lt;/li&gt;
&lt;li&gt;Only uses 1 tiny library, and even that dependency is optional.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It also has the following cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No support for middlewares.&lt;/li&gt;
&lt;li&gt;No tool akin to the Redux chrome debugger ☹️.&lt;/li&gt;
&lt;li&gt;Containers must be provided in a certain order if they have dependencies on each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this in mind, hopefully you now have a better idea of what sort of alternatives exist if your use-case doesn't demand something as bulky as Redux.&lt;/p&gt;

&lt;p&gt;If you want to employ this pattern but can't quite leave Redux, another alternative would be a using Redux Toolkit + Redux Ducks Pattern. The Redux Ducks approach works well if you're building a large application because it uses this container-focused methodology, but still keeps you in the ecosystem of Redux.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This is the Container pattern. If you're looking at using Redux in an app, I would take a serious look at the cost of doing so to determine if your application actually requires it. I think this pattern is a good place to start regardless, and because it's so small and modular you can migrate it into Redux in the future really easily.&lt;/p&gt;

&lt;p&gt;Overall, this pattern has helped me clean up my codebase a lot and remove state management from my list of pain-points when developing applications.&lt;/p&gt;

&lt;p&gt;Anyways, Let me know what you think and hopefully it will work well in your projects. Enjoy!&lt;/p&gt;

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

&lt;p&gt;Check me out to view more things like this: &lt;a href="https://spencerpauly.com" rel="noopener noreferrer"&gt;https://spencerpauly.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>redux</category>
      <category>typescript</category>
    </item>
    <item>
      <title>10 Pro-Tips for Incoming Computer Science Students in 2020</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Sun, 23 Aug 2020 23:23:38 +0000</pubDate>
      <link>https://forem.com/spencerpauly/10-pro-tips-for-incoming-computer-science-students-in-2020-2l3c</link>
      <guid>https://forem.com/spencerpauly/10-pro-tips-for-incoming-computer-science-students-in-2020-2l3c</guid>
      <description>&lt;p&gt;As we approach late august, the time is coming for college classes to kick off again. Whether your school is online or in-person, I believe there's a handful of things you can do to make this year a success. This article is a culmination tips targeted at Computer Science majors to help them have a successful year. This information has been curated from my four years of learning at university, along with various pieces of advice from other students, graduates and professors.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. You don't need to know how to program yet. And here's proof!
&lt;/h3&gt;

&lt;p&gt;Trust me, you don't need to know how to program going into a CS degree. Hell, the degree wouldn't exist if everyone was expected to come in knowing what they are doing already. Want proof of that? Here's Exhibit A:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/spencerpauly/Sorting-Algorithm" rel="noopener noreferrer"&gt;spencerpauly/Sorting-Algorithm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my first personal project I made halfway through freshman year. This is a suuuuper simple sorting program. Like 100 lines of code simple. But, at the time I was super proud of it and thought I had discovered some new amazing algorithm. The reason I'm sharing this is because the fact that I was proud enough of this tiny project to put it on Github should show how little I knew going into my CS degree.&lt;/p&gt;

&lt;p&gt;Now, just over 3 years later, I have a mobile app launched on the app store and have done various other medium-sized projects in the past 2 years. The path from bubble sort to app store can be a hard one, but trust me it's attainable. School will do a good job of teaching you the basics, so don't worry about how much you know going into the major. After you learn the fundamentals, it's up to you to gain more knowledge before you graduate. My other tips are aimed at helping you do that.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Ride the wave to mastery
&lt;/h3&gt;

&lt;p&gt;If you're like me then you'll constantly feel like you're in one of these two camps as you embark on your journey. Although it's pretty awesome to feel like a god all the time, it's not practical and you're bound to get stuck over and over again.&lt;br&gt;
I like to think of this paradigm as just riding the wave to mastery. You have to ride the up's and down's, but what you'll find is the general long-term trend will be an upward slope to mastery as you learn more things.&lt;br&gt;
My advice here would be to not get discouraged during the hard parts of the learning process. It takes a long time to learn these skills, so just relax and ride the wave.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Learn in public
&lt;/h3&gt;

&lt;p&gt;This is a concept I'm trying to do more and more. It's the idea that whenever you're learning something new you should do it in a public context. So if you're developing an app, build it in a way where others can follow your journey. You can do this by posting a weekly blog on medium or dev.to, or posting a daily update on twitter, or even making a youtube channel and sharing your learnings there.&lt;br&gt;
This has 2 benefits because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Employers LOVE this. Companies know that no intern is going to be a master of their craft and that's not what they're looking for either. Companies are looking for someone who's good at learning, good at communicating, and passionate for what they're doing. There's no better way to exemplify all these qualities than to have a repository of your thoughts and say "Look! This is everything I've learned this past year."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This will make you a better learner. Having a set-time each week where you sit down and reflect on what you learned and share a piece of that to the world helps you solidify that knowledge. It's also very motivating to see other people be engaged in the problems you're working on will give you the drive to keep going.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. You Need a Personal Website
&lt;/h3&gt;

&lt;p&gt;This is key. If you're going to "learn in public" it's a good idea to make a personal website that can give people one central place to view all the cool things you're up to. This is also a great programming project too, because it's something that you can make as simple or complicated as you want and once you finish it you can easily share it to the world.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bonus Tip: Don't be a perfectionist when building this website. I've redone my website 3 times in 3 years and plan to redo it again in the near future. It's more important to have a website than to have a perfect one.&lt;br&gt;
I have some classmates who built theirs with plain HTML and it works great! Hell I have professors who's websites are built in plain HTML. If you don't have an interest in design, making it minimal and purely functional is a great path to take.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5. Make Use of Free Student Perks!
&lt;/h3&gt;

&lt;p&gt;Take advantage of all your student discounts! You can ride these discounts really far and likely never have to pay for any cloud-hosting before you graduate. You can find these deals everywhere, but my favorite place to view student perks is Github Student Developer Pack. Some of my favorite deals from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/education/awseducate/" rel="noopener noreferrer"&gt;$100 of AWS Credits for Cloud Services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://education.github.com/pack" rel="noopener noreferrer"&gt;Free GitHub Pro While a Student&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://education.github.com/pack" rel="noopener noreferrer"&gt;Free Year of a NameCheap .me Domain Name&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/github-students/" rel="noopener noreferrer"&gt;$50 of Free DigitalOcean Cloud Hosting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/students" rel="noopener noreferrer"&gt;$200 of Free MongoDB Atlas Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;… and more!&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Learn the Difference Between the 3 Types of Computer Science Classes
&lt;/h3&gt;

&lt;p&gt;The Computer Science major has really 3 different types of classes. It's important to know the difference between these because some of these areas may not be as interesting to you and that's okay.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Algorithm Courses&lt;/strong&gt; (ex. Discrete Math, Finite Automata, Data Structures)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;These classes are what people are talking about when they say the Computer Science major has a lot of "math" in it. These classes are similar to math classes and teach you more of the theoretical-side of Computer Science. They'll teach you how to develop algorithms, how to write proofs, data structures and more. If you love these classes they can be a path towards grad school, a PHD, teaching, or research fields.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hardware / Low-Level Courses&lt;/strong&gt; (ex. Operating systems, Computer Networks, Computer architecture)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;These classes teach you what's going on in internally in a computer. You'll learn stuff such as CPU scheduling, networking, assembly programming, operating systems, permissions, etc etc. If you like these classes, this can lead you into a career doing computer engineering, robotics, OS design, or more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Programming Courses&lt;/strong&gt; (ex. Software Analysis &amp;amp; Design, Software Engineering)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;These courses will teach you how to write software. In these classes you'll learn object-oriented design, design patterns, databases, frontend design, git, project management and more. If you like these classes, they can lead to a career in web design, game development, backend engineer, software engineer and more. There's so many options it would be too many to list.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All of these classes are important. You'll find that the concepts of one will tie into another so pay attention to everything. You might first be introduced to a hypothetical concept in your algorithms class (like big-O notation), then later see it cropped up in a programming class (For determining the best way to structure your SQL query). That's typical and it's the reason all these classes exist.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bonus Tip: Don't load up your schedule with too many of 1 type of class in the same semester or you might get overwhelmed with too much of the same type of workload. This depends on the specific class, but it's generally a good rule to follow.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  7. Complete projects and labs early.
&lt;/h3&gt;

&lt;p&gt;Some courses can be very project based. Each of my programming-focused courses had about 8 labs and 5 or 6 projects of varying difficulty. This can be super stressful if you leave these to the last couple days, especially considering you probably won't know what you're doing.&lt;br&gt;
It helps to develop a pattern. I eventually got a pattern down of trying to complete projects the weekend before they were due and this helped a lot. This gives you the ability to step away and refresh your brain then come back and tackle a problem later. I still do this today!&lt;/p&gt;




&lt;h3&gt;
  
  
  8. Learn the Command-Line. It pops up everywhere.
&lt;/h3&gt;

&lt;p&gt;Mastering the unix command-line is one of the most practical skills you can learn in college. You should learn how to create, edit and delete files, navigate directories, move files around, edit documents with vim, and shell into other computers. This might not seem like the most important thing to learn at the time, especially if you're thinking "No but I don't need a command-line for X", but the fact is that everyone will need the command line to use git repositories, ssh into your production environment, etc. It's unavoidable.&lt;/p&gt;




&lt;h3&gt;
  
  
  9. Build a "Capstone Project" each semester
&lt;/h3&gt;

&lt;p&gt;This has been my favorite way to work on my programming skills. After each semester when I'm on Christmas or summer break I'll build a "Capstone Project" that solidifies everything I learned. This is a great way to stay in the habit of programming, build your resume, and build something that you actually want to use!&lt;/p&gt;

&lt;p&gt;One of my favorites of these projects is my Spotify web app that lets me view my most listened to tracks and artists:&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://spotify.spencerpauly.com/" rel="noopener noreferrer"&gt;spotify.spencerpauly.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Doing projects you're interested like this will make it something you want to finish so my recommendation is to build something that YOU want to use. Even if it already exists, that doesn't matter. Just build what you would use.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. Internships are Attainable.
&lt;/h3&gt;

&lt;p&gt;The job environment might be changing due to COVID, but trust me there will still be internships available. The key is to know where to find them and how to have the skills they're looking for in candidates. If you do the other items on this list, such as learn in public, have a personal website, and build capstone projects, you'll be an attractive intern no matter what year you are.&lt;/p&gt;

&lt;p&gt;Here's some other tips I have for getting internships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Get out of the mindset that you're "not prepared" for an internship. Everyone is still learning through college so let the companies be the judge of if you're prepared or not, don't make that decision for them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There's always internship opportunities popping up. I started applications around October last year and got an internship in November. Some students started even earlier. The summer before that I got my internship during finals week right before summer. New opportunities are popping up all the time, so be on the lookout consistently through the school year.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use State-Funded Internship boards if available. If you live in Minnesota, &lt;a href="https://scitechmn.org/" rel="noopener noreferrer"&gt;https://scitechmn.org/&lt;/a&gt; is a great resource that I recommend. Local internship boards have a smaller competition pool and give you a more personal application process than something like Indeed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;I hope you find this valuable and if you have any more tips please share them in the comments!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fewn48k8gi0rfy21nrz0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fewn48k8gi0rfy21nrz0d.png" alt="Alt Text" width="800" height="571"&gt;&lt;/a&gt;&lt;br&gt;
Check me out: &lt;a href="https://spencerpauly.com" rel="noopener noreferrer"&gt;https://spencerpauly.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>computerscience</category>
      <category>codenewbie</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What tips would you have for incoming Computer Science freshman?</title>
      <dc:creator>Spencer Pauly</dc:creator>
      <pubDate>Wed, 19 Aug 2020 14:05:36 +0000</pubDate>
      <link>https://forem.com/spencerpauly/what-tips-would-you-have-for-incoming-computer-science-freshman-2f1o</link>
      <guid>https://forem.com/spencerpauly/what-tips-would-you-have-for-incoming-computer-science-freshman-2f1o</guid>
      <description>&lt;p&gt;I’m writing an article on the subject and I think I have a couple good tip but I want to get your pro tips aswell.&lt;/p&gt;

&lt;p&gt;What’s things you wish you knew going in to a CS degree or college in general?&lt;/p&gt;

&lt;p&gt;What’s something you had a misconception about?&lt;/p&gt;

&lt;p&gt;What would you do differently if you could?&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>career</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
