<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luke Czyszczonik</title>
    <description>The latest articles on DEV Community by Luke Czyszczonik (@czystyl).</description>
    <link>https://dev.to/czystyl</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%2F776219%2Fec901033-e102-413f-a0fc-75e1f030ccc1.jpeg</url>
      <title>DEV Community: Luke Czyszczonik</title>
      <link>https://dev.to/czystyl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/czystyl"/>
    <language>en</language>
    <item>
      <title>🪄 gql.tada makes a GraphQL great again</title>
      <dc:creator>Luke Czyszczonik</dc:creator>
      <pubDate>Thu, 29 Feb 2024 10:36:03 +0000</pubDate>
      <link>https://dev.to/czystyl/gqltada-makes-a-graphql-great-again-15m2</link>
      <guid>https://dev.to/czystyl/gqltada-makes-a-graphql-great-again-15m2</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@jeztimms"&gt; Jez Timms &lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-bunch-of-fireworks-that-are-in-the-dark-r4lM2v9M84Q"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I began exploring the GraphQL ecosystem in 2018. At that time, REST APIs were a significant part of my daily work, but I was always exploring and looking for new challenges. During that period, I invested much of my time transitioning from the PHP ecosystem to React, React Native, Node.js, GraphQL, and TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaving GraphQL
&lt;/h2&gt;

&lt;p&gt;While GraphQL enhanced communication between frontend and backend, there were several gaps and obstacles in making it work effectively. Tools like Apollo and now &lt;a href="https://commerce.nearform.com/open-source/urql/docs/"&gt;urql&lt;/a&gt; have improved the client-side experience with GraphQL. However, ensuring a type-safe experience requires using &lt;a href="https://the-guild.dev/graphql/codegen/docs/guides/react-vue"&gt;GraphQL CodeGen&lt;/a&gt;. &lt;a href="https://the-guild.dev/"&gt;The Guild&lt;/a&gt; has made remarkable efforts to streamline this experience, yet there is still room for improvement.&lt;/p&gt;

&lt;p&gt;I transitioned from the GraphQL ecosystem to the &lt;a href="https://trpc.io/"&gt;tRPC&lt;/a&gt; world to enhance my daily workflow more than a year ago. This shift was swift and relatively issue-free, resulting in faster and simpler project development backed by TanstackQuery on the front end. Although some costs were involved, the overall benefits and experiences have made it worthwhile.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪄 gql.tada Makes GraphQL Great Again!
&lt;/h2&gt;

&lt;p&gt;Since last week, I've been testing &lt;a href="https://gql-tada.0no.co/"&gt;gql.tada&lt;/a&gt;, the new library created by &lt;a href="https://twitter.com/_philpl"&gt;Phil Pluckthun&lt;/a&gt; and &lt;a href="https://twitter.com/JoviDec"&gt;Jovi De Croock&lt;/a&gt; that eliminates the need for codegen and seamlessly integrates GraphQL with TypeScript like never before.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gql-tada.0no.co/get-started/installation/"&gt;initialization process&lt;/a&gt; is straightforward, requiring only three lines of code in &lt;code&gt;tsconfig.json&lt;/code&gt; and one file to export the typed client. The best part is that everything works without additional background processes and is baked into TypeScript.&lt;/p&gt;

&lt;p&gt;Three features have made me miss the GraphQL ecosystem again! Let's explore them and see how they change the way you work with GraphQL on the client side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autocomplete
&lt;/h3&gt;

&lt;p&gt;The first notable feature is the autocomplete, which feels like having a GraphQL playground built into the TypeScript editor. For me, autocomplete is essential when working with GraphQL. The visibility of available queries, along with their corresponding fields, mutations, and arguments, enhances the developer experience.&lt;/p&gt;

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

&lt;p&gt;Another thing to note is the argument handling by the urql client. It quickly provides feedback about missing arguments or incorrect types. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  Fragment masking
&lt;/h3&gt;

&lt;p&gt;The next one is &lt;a href="https://gql-tada.0no.co/guides/fragment-colocation/#fragment-masking"&gt;Fragment Masking&lt;/a&gt;. Gql.tada adds a layer of "security" to Fragments by preventing accidental access to Fragment types. This feature stops the direct use of fragment data in components without explicitly reading the data. Instead, you must use the &lt;code&gt;readFragment()&lt;/code&gt; hook to explicitly read (unwind) the fragment data type. You can learn more about this feature &lt;a href="https://gql-tada.0no.co/guides/fragment-colocation/#fragment-masking"&gt;here&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;GraphQL Fragments can help reduce duplications, as multiple types within the GraphQL Schema can utilize the same fragment. This creates boundaries for composing data structures. As you might have seen in the video, gql.tada also warns you about unused fragments in your codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unused warning
&lt;/h3&gt;

&lt;p&gt;One of the advantages of GraphQL is its requirement for explicitness; you always have to specify the data set you want to fetch. This can lead to overfetching when unused data is not immediately visible, particularly without an effective tooling. However, with gql.tada, this problem is resolved as it immediately highlights unused fields as you type.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;GraphQL demands a degree of explicitness when specifying the data developers want to use. Without appropriate tooling, this could be cumbersome. However, gql.tada fills this gap perfectly. Its features make working with GraphQL enjoyable once more!&lt;/p&gt;

&lt;p&gt;All the codebase used for this blog post is here: &lt;a href="https://github.com/czystyl/expo-tada"&gt;https://github.com/czystyl/expo-tada&lt;/a&gt;&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Safe component state with useReducer and TypeScript</title>
      <dc:creator>Luke Czyszczonik</dc:creator>
      <pubDate>Thu, 12 Jan 2023 19:31:09 +0000</pubDate>
      <link>https://dev.to/czystyl/safe-component-state-with-usereducer-and-typescript-2m2f</link>
      <guid>https://dev.to/czystyl/safe-component-state-with-usereducer-and-typescript-2m2f</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@nelly13?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Nelly Antoniadou&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/07rYS9_iEkc?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using multiple useState's to control component state is a common practice in React codebases, but it can result in unexpected behavior, such as a forever loading component or a disabled submit button.&lt;/p&gt;

&lt;p&gt;Let's see what such components usually look like:&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="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleEmailSend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isEmailValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;setErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendToAPI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can imagine that one missing setState can make an invalid UI state that we do not want.&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;useReducer&lt;/code&gt; to make the code much cleaner and less error-prone.&lt;/p&gt;

&lt;p&gt;Let’s start by defining all the different possible component states we want to handle:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Typing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Fetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetching&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FetchSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FetchFailed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used type intersection to distinguish the correct type based on the type property. Our reducer state will be a union of all defined above types plus email filed.&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResponseState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Typing&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Fetching&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FetchSuccess&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FetchFailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BaseState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BaseState&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ResponseState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reducer requires action types, which typically include a "type" property. We can utilize the valid UI states that we've already defined, eliminating the need for duplicating code when defining our actions.&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Fetching&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Typing&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FetchSuccess&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FetchFailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetching&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reducer is straightforward, thanks to the reuse of types from the reducer state for the actions, and the fact that their shape aligns with the reducer action pattern. The only exception is the success action, where we also clear the email input value. By connecting the reducer actions and state in this manner, unexpected states should no longer be an issue.&lt;/p&gt;

&lt;p&gt;Let's see how we can simplify our handlers:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleEmailSend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
 &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetching&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendToAPI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component render is also pretty clear and easy to understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorMessage&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example dismissed the invalid states and made our component safe, so we can assume that we archive the goal!&lt;/p&gt;

&lt;p&gt;Please let me know in the comments what you think about that kind of reducer typing and if you have used it before! &lt;/p&gt;

&lt;p&gt;If you want to explore the full example, &lt;a href="https://stackblitz.com/edit/safe-use-reducer?file=src/FormReducer.tsx" rel="noopener noreferrer"&gt;here is the live example&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>writing</category>
    </item>
    <item>
      <title>Google Cloud Functions in monorepo</title>
      <dc:creator>Luke Czyszczonik</dc:creator>
      <pubDate>Wed, 16 Feb 2022 13:25:02 +0000</pubDate>
      <link>https://dev.to/czystyl/google-cloud-functions-in-monorepo-44ak</link>
      <guid>https://dev.to/czystyl/google-cloud-functions-in-monorepo-44ak</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@alevisionco?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;alevision.co&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;The Google Cloud Functions (&lt;strong&gt;GCF&lt;/strong&gt;) and serverless architecture have gained a lot of attention during the last few years. Serverless functions intend to be small and easy to use. With GCF, you can start from a single JavaScript file, and you do not need anything else. &lt;/p&gt;

&lt;p&gt;I recently worked with the system that has ten separate Github repositories. All of those repositories are somehow connected and depend on one another. This situation decreased the development speed and experience, so I merged all the pieces into a monorepo. The migration went smooth. &lt;br&gt;
The API services use the internal packages, so I didn’t need to publish them into private NPM anymore. This change increased development speed, experience, and confidence that services use the correct versions of packages. The whole codebase was written in TypeScript, which was an obvious benefit from monorepo because I could use features like &lt;a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping" rel="noopener noreferrer"&gt;path mapping&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Unfortunately, I ran into a few issues with GCFs and the use of local packages that stopped me from finishing the integration. I looked through a lot of Github Issues and StackOverflow threads and I saw that people had similar problems to mine. I tried a few solutions from those threads but none of them were good for my use case so I ended up with a different solution.&lt;/p&gt;

&lt;p&gt;Let me describe some of the steps that I ran into to make the GCFs work with the monorepo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monorepo and Typescript
&lt;/h3&gt;

&lt;p&gt;I used the Yarn Workspace to manage the monorepo dependencies. In the monorepo, every package and function uses TypeScript so path mapping was the way to go for me as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauuxrmmwb3vobpv1dmx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauuxrmmwb3vobpv1dmx0.png" alt="yarn workspace configuration"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4moyhm3wqc4qr3lvjoos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4moyhm3wqc4qr3lvjoos.png" alt="TypeScript path mapping configuration"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;p&gt;The development process of GCF is not as simple as I expected. After some time I managed to establish this process. &lt;/p&gt;

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

&lt;p&gt;In line &lt;strong&gt;8.&lt;/strong&gt; we have &lt;code&gt;yarn dev&lt;/code&gt; script that is used in development. The script generates entry file (if needed, but this will be described below) and run two scripts. One of them is build process in watch mode. The second is responsible for re-run function to see the changes. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GCF do not support hot reloading by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using local package
&lt;/h3&gt;

&lt;p&gt;Up until now, development and deployment works smoothly and without any issues. To get this working, I modified the TypeScript configuration to include all the code related packages into the distribution directory. This step changed how the distribution directory looks and also affected the development and deployment process.&lt;/p&gt;

&lt;p&gt;After that change, the distribution directory contains function source code and all related packages in the same shape that they are structured in the monorepo. &lt;/p&gt;

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

&lt;p&gt;Another problem was that after building code using the TypeScript compiler I still have original paths to local packages, see the line 7. &lt;/p&gt;

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

&lt;p&gt;To solve this issue I decided to use the &lt;code&gt;module-alias&lt;/code&gt; package and custom “entry point” file to build the function code.  &lt;/p&gt;

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

&lt;p&gt;These solutions allow me to have a good local development experience and I also have the single entry point for my deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  GCF deployment dependencies
&lt;/h3&gt;

&lt;p&gt;The last problem was missing that some dependencies and &lt;code&gt;yarn.lock&lt;/code&gt; was missing during deployment. The function’s &lt;code&gt;package.json&lt;/code&gt; file didn’t include the dependencies from used local packages.&lt;/p&gt;

&lt;p&gt;To have the correct dependencies and their versions, I had to copy the &lt;code&gt;yarn.lock&lt;/code&gt; file into the function directory and add all the used packages’ dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;You can find all described solutions in the example repository: &lt;a href="https://github.com/productbrew/gcf-monorepo" rel="noopener noreferrer"&gt;https://github.com/productbrew/gcf-monorepo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gcf</category>
      <category>monorepo</category>
      <category>typescript</category>
      <category>googlecloudfunctions</category>
    </item>
    <item>
      <title>Elixir in the eyes of Node.js developer</title>
      <dc:creator>Luke Czyszczonik</dc:creator>
      <pubDate>Mon, 20 Dec 2021 13:50:33 +0000</pubDate>
      <link>https://dev.to/czystyl/elixir-in-the-eyes-of-nodejs-developer-fee</link>
      <guid>https://dev.to/czystyl/elixir-in-the-eyes-of-nodejs-developer-fee</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@kaizennguyen?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Kaizen Nguyễn&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I got into Elixir some time ago, but at that time, I was more interested in statically typed languages. I didn't exclude Elixir at that time, but instead, I moved it to a second plan. One of the signals to give Elixir a try was the talk from &lt;em&gt;Saša Jurić - The Soul of Erlang and Elixir&lt;/em&gt;. I highly recommend watching this talk. I discovered that the BEAM VM and Elixir features could offer many benefits. So I decided to try and see how all the pieces are working together in an actual application. I'd like to share some critical ecosystem points that convinced me to try.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community&lt;/strong&gt; &lt;br&gt;
One of the first things that I noticed when I started was the community libraries. Almost all the libraries shared the same structure and had all the API interfaces generated along with the type spec. So I searched for a few libraries that I often use, like web framework, GraphQL implementation or Database management. I can say that all of them look solid, and the documentation also contains a lot of guidelines, so I didn't need to leave the page to have a good understanding of them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Phoenix framework&lt;/strong&gt;&lt;br&gt;
The Phoenix is a web framework that makes building web servers easy and fast. Great thing is that Phoenix has a built-in code generator. This generator is done via the mix task and you can generate almost all needed parts for creating an endpoint, context or database schema. Additionally, the documentation and guidelines described in the next point make you much more comfortable in the first place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing and documentation&lt;/strong&gt;&lt;br&gt;
When looking back on different projects, documentation and testing are some of the forgotten things during development. Within the Elixir, those things are built in the language, making a considerable change for development and maintenance. You can write the documentation and examples right next to the code, and as we advance, you can turn these examples into quick tests. It was a nice thing that convinced me to write more tests and documentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GenServer&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The GenServer allows you to abstract logic around small services. For example, all these services might have a separate state and business logic encapsulated inside. The service code is executed as a lightweight BEAM process, which is fast compared to standalone microservice solutions. Therefore, you do not need any extra HTTP layer or queue to communicate within the service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type system, pattern matching and language itself&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
I need to say that I'm a big fan of statically typed languages. So, when I heard about the Elixir for the first time, missing a type system was a big downside for me. Also, I understand that making such a dynamic language static would be a big challenge. To fill this gap, I used Dialixir and Typespecs. The experience is slightly different, but you have some tangibility of the type system, called success typing.&lt;/p&gt;

&lt;p&gt;Elixir has a functional language style that fits my personality best, but everyone can feel differently. On top of this, you have a great set of language features like With statements, function guards, the pipe operator and excellent pattern matching.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BEAM virtual machine&lt;/strong&gt;&lt;br&gt;
I think it was one of the biggest deal-breaker for using the Elixir heavier. The BEAM architecture, combined with the language features described above, make it a great combo! &lt;br&gt;
The virtual machine is responsible for running your code in small, cheap and fast processes. One of the philosophies that are coming from Erlang is &lt;code&gt;Let it fail&lt;/code&gt;. The philosophy allows writing the system that is working more consistently and reliably. I could compare this to our systems like Linux, Windows or macOS. The system is working, but some programs that we installed are crashing from time to time, but usually, your system is still working, and only what you have to do is open your program once again. Like BEAM VM, one process might crash, but the whole system is still working as usual. &lt;/p&gt;

&lt;p&gt;Overall, I feel surprised how good working with Elixir was. One of the gaps is the lack of a static type system. To fill this gap, I used Credo, Dialixir and TypeSpecs to analyze the codebase statically. The language features make writing the code quicker, easier and cleaner to maintain. For example, built-in documentation and testing might turn your codebase into an environment that is a pleasure to work with. The last piece of this whole stack is that all of this runs on BEAM VM, which is the cherry on the cake! So I need to say that the lack of a static type system is no longer a significant disadvantage with such a combo! &lt;/p&gt;

&lt;p&gt;It is the first blog about my elixir journey, and I plan to share more detailed knowledge soon in my next blog.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

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