<?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: Remote</title>
    <description>The latest articles on DEV Community by Remote (@remote).</description>
    <link>https://dev.to/remote</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%2Forganization%2Fprofile_image%2F5318%2Ff71a288d-b164-4285-a1b0-5125e83a2fb0.png</url>
      <title>DEV Community: Remote</title>
      <link>https://dev.to/remote</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/remote"/>
    <language>en</language>
    <item>
      <title>Announcing the Devs For Ukraine Conference</title>
      <dc:creator>Cassidy Williams</dc:creator>
      <pubDate>Mon, 04 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/remote/announcing-the-devs-for-ukraine-conference-dl1</link>
      <guid>https://dev.to/remote/announcing-the-devs-for-ukraine-conference-dl1</guid>
      <description>&lt;p&gt;In February 2022, Russia and its forces senselessly attacked Ukraine. The violence and the suffering inflicted on the people in Ukraine is very real. We want to help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing &lt;a href="https://www.devsforukraine.io/"&gt;Devs For Ukraine&lt;/a&gt;, a free, online charity conference with the goal of raising funds and providing support to Ukraine.
&lt;/h2&gt;

&lt;p&gt;On April 25th and 26th, join 17 speakers from around the globe to learn about career growth, team leadership, tech’s ability to create a more equitable world, and more.&lt;/p&gt;

&lt;p&gt;Our goal for the event is to raise $15,000 for these non-governmental organizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.comebackalive.in.ua/"&gt;Come Back Alive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://razomforukraine.org/"&gt;Razom For Ukraine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redcross.org.ua/en/2022/02/donate-to-support-the-ukrainian-red-cross-to-help-civilians-in-this-difficult-time-for-ukraine/"&gt;Red Cross&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pck.pl/na-pomoc-ukrainie/"&gt;Polski Czerwony Krzyż (PCK)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://voices.org.ua/en/"&gt;Voices of Children&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pah.org.pl/sos-ukraina/"&gt;Polska Akcja Humanitarna (PAH&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-ukraine.org/en/"&gt;Insight Ukraine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gofundme.com/f/support-vulnerable-black-people-in-ukraine"&gt;Coalition To Support Black People In Ukraine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The event will be free to attend and is run by volunteers, but we ask everyone to donate. &lt;strong&gt;All of the funds will be donated to the benefit of Ukraine.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How you can help
&lt;/h2&gt;

&lt;p&gt;If you’d like to help our cause, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.devsforukraine.io/"&gt;Register to attend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Share this event with your communities (&lt;a href="https://twitter.com/intent/tweet?text=I%27m%20going%20to%20DevsForUkraine,%20a%20free%20conference%20to%20benefit%20Ukraine%20with%2017%20awesome%20speakers!%20Will%20I%20see%20you%20there?&amp;amp;url=devsforukraine.io"&gt;click here to tweet&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.devsforukraine.io/?modal=donate"&gt;Donate directly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re looking forward to seeing you at the event!&lt;/p&gt;

</description>
      <category>ukraine</category>
      <category>conference</category>
      <category>free</category>
      <category>charity</category>
    </item>
    <item>
      <title>Introducing phx_gen_solid</title>
      <dc:creator>Cassidy Williams</dc:creator>
      <pubDate>Wed, 16 Mar 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/remote/introducing-phxgensolid-5178</link>
      <guid>https://dev.to/remote/introducing-phxgensolid-5178</guid>
      <description>&lt;p&gt;At Code BEAM 2020, our CTO and co-founder Marcelo Lebre introduced &lt;a href="https://www.youtube.com/watch?v=xWqOR-cdIUQ"&gt;Four Patterns to Save your Codebase and your Sanity&lt;/a&gt;. Remote has been utilizing these patterns for over a year now, and the results have been incredible! The speed at which we can build out new ideas and features while maintaining a consistent structure throughout all parts of the codebase is truly remarkable.&lt;/p&gt;

&lt;p&gt;The patterns outlined below have served us well, but they do come with a drawback: &lt;strong&gt;boilerplate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;phx_gen_solid aims to solve the boilerplate problem as well as educate and empower others to &lt;strong&gt;create&lt;/strong&gt; with the building blocks described here.&lt;/p&gt;

&lt;h2&gt;
  
  
  SOLID principles
&lt;/h2&gt;

&lt;p&gt;The patterns from the talk build on a set of principles first introduced in &lt;em&gt;Design Principles and Design Patterns&lt;/em&gt; by Robert Martin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt; ingle-responsibility principle: "There should never be more than one reason for a class to change." In other words, every class should have only one responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt; pen-closed principle: "Software entities...should be open for extension, but closed for modification."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L&lt;/strong&gt; iskov substitution principle: "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt; nterface segregation principle: "Many client-specific interfaces are better than one general-purpose interface.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt; ependency inversion principle: "Depend upon abstractions, [not] concretions.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s no need to deep dive into each of these, but they are important to keep in mind as they are the reasons behind each of the following solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finders, handlers, services, and values
&lt;/h2&gt;

&lt;p&gt;These four patterns are the building blocks behind everything we build in our Phoenix app at Remote. Surprisingly, there is very little overlap between each, and features usually find a happy home in one of the following ideologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finders
&lt;/h3&gt;

&lt;p&gt;Finders fetch data. They don’t mutate nor write, only read and present.&lt;/p&gt;

&lt;p&gt;Non-complex database queries may also exist in Phoenix Contexts. A query can be considered complex when there are several conditions for filtering, ordering, and/or pagination. Rule of thumb is when passing a params or opts Map variable to the function, a Finder is more appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organized by application logic&lt;/li&gt;
&lt;li&gt;Reusable across Handlers and Services&lt;/li&gt;
&lt;li&gt;Focuses on achieving one single goal&lt;/li&gt;
&lt;li&gt;Exposes a single public function: find&lt;/li&gt;
&lt;li&gt;Read data structure&lt;/li&gt;
&lt;li&gt;Uses Values to return complex data&lt;/li&gt;
&lt;li&gt;Finders only read and look up data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call any services&lt;/li&gt;
&lt;li&gt;Create/modify data structures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of a finder that finds a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Finder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserWithName&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_user_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:not_found&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:invalid_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handlers
&lt;/h3&gt;

&lt;p&gt;Handlers are orchestrators. They exist only to dispatch and compose. A handler orders execution of tasks and/or fetches data to put a response back together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organize by business logic, domain, or sub-domain&lt;/li&gt;
&lt;li&gt;Orchestrate high level operations&lt;/li&gt;
&lt;li&gt;Command services, finders, values or other handlers&lt;/li&gt;
&lt;li&gt;Multiple public functions&lt;/li&gt;
&lt;li&gt;Keep controllers thin&lt;/li&gt;
&lt;li&gt;Make it easy to read&lt;/li&gt;
&lt;li&gt;Flow control (if, case, pattern match, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directly create/modify data structures&lt;/li&gt;
&lt;li&gt;Execute any read/write operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of a handler that creates a user, sends a notification, and fetches some data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Registration&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;CreateUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SendNotification&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Finder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserWithName&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;setup_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;CreateUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="ss"&gt;:ok&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;SendNotification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="n"&gt;user_details&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;UserWithName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_details&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;Services are the execution arm. Services execute actions, write data, invoke third-party services, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organize by application logic&lt;/li&gt;
&lt;li&gt;Reusable across handlers and other services&lt;/li&gt;
&lt;li&gt;Commands services, finders and values&lt;/li&gt;
&lt;li&gt;Focuses on achieving one single goal&lt;/li&gt;
&lt;li&gt;Exposes a single public function: call&lt;/li&gt;
&lt;li&gt;Create/modify data structures&lt;/li&gt;
&lt;li&gt;Execute and take actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a service to achieve multiple goals&lt;/li&gt;
&lt;li&gt;Call handlers&lt;/li&gt;
&lt;li&gt;If too big, you need to break it into smaller services or your service is actually a handler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of a service that creates a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateUser&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ActivityLog&lt;/span&gt;
  &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
         &lt;span class="ss"&gt;:ok&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;ActivityLog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;changeset&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="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:invalid_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

      &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Values
&lt;/h3&gt;

&lt;p&gt;Values allow us to compose data structures such as responses, intermediate objects, etc. You’ll find that values are very helpful in returning JSON from an API, and in most cases trims our &lt;a href="https://hexdocs.pm/phoenix/views.html#rendering-json"&gt;View render functions&lt;/a&gt; into just a single line, MyValue.build(some_struct).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organize by application logic&lt;/li&gt;
&lt;li&gt;Reusable across handlers, services, and finders&lt;/li&gt;
&lt;li&gt;Focuses on composing a data structure&lt;/li&gt;
&lt;li&gt;Exposes a single public function: build&lt;/li&gt;
&lt;li&gt;Use composition to build through simple logic&lt;/li&gt;
&lt;li&gt;Only returns a &lt;a href="https://hexdocs.pm/elixir/List.html"&gt;List&lt;/a&gt; or a &lt;a href="https://hexdocs.pm/elixir/Map.html"&gt;Map&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call any services, handlers or finders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of a value that builds a user object to be used in a JSON response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Remoteoss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Value&lt;/span&gt;

  &lt;span class="nv"&gt;@valid_fields&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_fields&lt;/span&gt; &lt;span class="p"&gt;\\\\&lt;/span&gt; &lt;span class="nv"&gt;@valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;When building an application as large as Remote’s (almost 400k lines!), it becomes tedious to write the same sort of structure over and over. We want to get into the business logic and the specifics as fast as possible. phx_gen_solid gets us to the fun part faster by generating as much boilerplate as we can right away. We can then tweak and fine-tune the specifics in any way we like! Hopefully, the generators are useful, and at the very least phx_gen_solid can act as a resource to learn a few new patterns or tricks!&lt;/p&gt;

&lt;p&gt;phx_gen_solid is still in its infancy, but it can already assist with one of the more complicated parts of the above patterns, values.&lt;/p&gt;

&lt;p&gt;You can add phx_gen_solid to your Phoenix app by adding the following to your mix.exs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phx_gen_solid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thenn install and compile the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  An example in action
&lt;/h3&gt;

&lt;p&gt;All phx_gen_solid generators follow the same structure as the Phoenix tasks you’re familiar with already, Context SchemaSingular schema_plural [fields].&lt;/p&gt;

&lt;h4&gt;
  
  
  Generating a simple Value
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt; &lt;span class="n"&gt;phx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;solid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;slug&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce the following code in my_app/accounts/values/user.ex&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Value&lt;/span&gt;

  &lt;span class="nv"&gt;@valid_fields&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_fields&lt;/span&gt; &lt;span class="p"&gt;\\\\&lt;/span&gt; &lt;span class="nv"&gt;@valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valid_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have defined your “Composer” with all the helpers to build values, you can specify it with the flag --value-module MyApp.Composition.Value, and the alias used in the generator will become alias MyApp.Composition.Value.&lt;/p&gt;

&lt;p&gt;If you would like to generate the recommended Value composer, simply pass the --helpers flag along with the command. It will populate the context my_app/value.ex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Remote has carefully crafted a workflow for engineers that allows us to iterate quickly and give our complete focus to the problem at hand. It’s a beautiful symphony of stakeholders, product managers, designers, and engineers working together towards a larger goal. The funny thing is, in a space where common problems are uncommon, we still find inefficiencies in what remains. It’s human nature, but it fuels progress.&lt;/p&gt;

&lt;p&gt;If you’re interested in contributing, head over to our &lt;a href="https://github.com/remoteoss/phx_gen_solid"&gt;GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The documentation for phx_gen_solid is also available over on &lt;a href="https://hexdocs.pm/phx_gen_solid/overview.html"&gt;hexdocs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing React URL Modal</title>
      <dc:creator>Cassidy Williams</dc:creator>
      <pubDate>Wed, 16 Mar 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/remote/introducing-react-url-modal-4ocd</link>
      <guid>https://dev.to/remote/introducing-react-url-modal-4ocd</guid>
      <description>&lt;p&gt;Here at Remote, we have &lt;a href="https://github.com/remoteoss"&gt;a shiny new GitHub organization&lt;/a&gt; where we’ll be open sourcing packages and libraries we’ve built for the world to see (and hopefully benefit from)! And — our first ever npm package is officially live!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remoteoss/react-url-modal"&gt;React URL Modal&lt;/a&gt; is a React library to help you keep track of your modal state using the URL. More specifically, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lets your modals in your applications have URLs&lt;/li&gt;
&lt;li&gt;Encodes all the parameters sent to a modal&lt;/li&gt;
&lt;li&gt;Supports React Portals&lt;/li&gt;
&lt;li&gt;Works with any framework (as it uses &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API"&gt;the History API&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s headless, minimal, and ready to use now!&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use the React URL Modal?
&lt;/h2&gt;

&lt;p&gt;You can install the library into your existing React projects via npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; npm i react-url-modal

# or

&amp;gt; yarn add react-url-modal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Or, you can manually &lt;a href="https://github.com/remoteoss/react-url-modal"&gt;install it locally from GitHub&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;From there, you can drop in the library wherever you’d like. Here’s an example of what that can look like:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;URLModal&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="s2"&gt;react-url-modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ExampleModalComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SomeOtherExampleModalComponent&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;./Modals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;URLModal&lt;/span&gt;
    &lt;span class="na"&gt;modals&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;exampleModal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleModalComponent&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;otherModal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SomeOtherExampleModalComponent&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where do I go from here?
&lt;/h2&gt;

&lt;p&gt;We’ve got some &lt;a href="https://react-url-modal.vercel.app/"&gt;more examples&lt;/a&gt; and &lt;a href="https://github.com/remoteoss/react-url-modal#documentation"&gt;API documentation&lt;/a&gt; for you to get started! We'd also love to hear about your bugs, feature requests, and use cases &lt;a href="https://github.com/remoteoss/react-url-modal/issues"&gt;in the repository&lt;/a&gt;. See you there!&lt;/p&gt;

</description>
      <category>react</category>
      <category>modal</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
