<?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: Gerardo Sandoval</title>
    <description>The latest articles on DEV Community by Gerardo Sandoval (@gerardosandoval).</description>
    <link>https://dev.to/gerardosandoval</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%2F75292%2Fef0ab832-e13a-40a3-8dd3-499b4405ad74.jpeg</url>
      <title>DEV Community: Gerardo Sandoval</title>
      <link>https://dev.to/gerardosandoval</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gerardosandoval"/>
    <language>en</language>
    <item>
      <title>Backend decisions: Webhooks, File Uploading, and API Versioning</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Tue, 18 Apr 2023 15:16:28 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/backend-decisions-webhooks-file-uploading-and-api-versioning-12ng</link>
      <guid>https://dev.to/gerardosandoval/backend-decisions-webhooks-file-uploading-and-api-versioning-12ng</guid>
      <description>&lt;p&gt;As a backend engineer, we face many decisions when building APIs, some of them are easy to make and some others are not that easy because of the several existent solutions for a specific problem, deciding which one is the best fit can become a nightmare if you do not assess it correctly. In this article, we'll cover three common topics: handling webhooks, file uploading, and API versioning, and for each one I'll describe few facts we can identify to help us easily make the correct decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webhooks: One Endpoint or Many?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Webhooks are a way for your API to notify other services or get notified of events that occur. When designing your webhook system, one question that often arises is whether to use a single endpoint to handle all possible events or to create separate endpoints for each event.&lt;/p&gt;

&lt;p&gt;The advantage of a single endpoint is that it simplifies the codebase and reduces maintenance overhead. All webhook payloads can be parsed and processed in one place, this is great! However, this can become unwieldy as the number of events grows, leading to complex branching logic, hard to debug or track, and potential performance issues, this is not so great...&lt;/p&gt;

&lt;p&gt;On the other hand, having separate endpoints for each type of event allows for more fine-grained control and easier scaling. Nonetheless, this approach can lead to a bloated codebase and increased maintenance overhead, a way to reduce that overhead is to have an adequate separation of concerns in your endpoints. Always aim to separate or group your endpoints by business logic, example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you have an integration with a payment gateway, you can separate and group your endpoints by specific models: payments, invoices, subscriptions, etc. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, the decision depends on your specific use case, but if we could write a quick rule of thumb, it would be the next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you have a small number of events and don't anticipate many more, a single endpoint may be the simpler solution. &lt;/li&gt;
&lt;li&gt;If you have many events or anticipate adding more in the future, consider using separate endpoints for each event. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, basically it just depends on the number of webhook events that you are handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File Uploading: Synchronous vs. Asynchronous&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When it comes to file uploading, there are different ways to do it, each with its own advantages and disadvantages. One common decision is whether to upload files synchronously or asynchronously, should we upload files before submission or wait until the submit buttons is clicked?&lt;/p&gt;

&lt;p&gt;Synchronous file uploading means the file is uploaded when the form is submitted. This approach is simpler to implement, as it doesn't require additional background processing. However, it can lead to slow response times if the file is large, as the user has to wait for the file to finish uploading before getting a response. &lt;/p&gt;

&lt;p&gt;Asynchronous file uploading means the file is uploaded in the background, even before the form is submitted. This approach allows for faster response times and a better user experience. The user does not have to wait until the file is uploaded to see the new page. However, it requires additional background processing and can be more complex to implement.&lt;/p&gt;

&lt;p&gt;When deciding which approach to use, consider the size of the files being uploaded and the user experience you want to provide.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you expect large files, asynchronous uploading may be the better choice. You can upload the files even before the form is submitted, this would give the user a great experience.&lt;/li&gt;
&lt;li&gt;If you want to provide a simple and straightforward user experience and make a quick implementation, then synchronous uploading may be the better option, just take in mind that the file upload time depends on the bandwidth of the connection and can sometimes take long, some users can try clicking somewhere else or reloading the page because they believe that there is a problem with the webpage, and then mess everything up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API Versioning: Why and How&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API versioning is the practice of creating new versions of your API as it evolves over time. This allows you to add new features, fix bugs, and make breaking changes without affecting existing clients. Even when your API is private and it serves only your own client, these practices may be needed.&lt;/p&gt;

&lt;p&gt;Note that is a good practice to follow a versioning schema like &lt;a href="https://semver.org/"&gt;semver&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There are different approaches to API versioning, but the most common ones are adding version numbers to the endpoint or using custom headers to indicate the version. Adding version numbers to the endpoint makes it easy for clients to switch between versions, but can lead to cluttered code and bloated APIs. Using custom headers can provide a cleaner API, but may require more work on the client side to switch between versions.&lt;/p&gt;

&lt;p&gt;When deciding how to version your API, consider the tradeoffs between simplicity and flexibility.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding version numbers to the endpoint is a simpler approach, but can lead to cluttered code. More code, more work.&lt;/li&gt;
&lt;li&gt;Using custom headers can provide a cleaner API, but may require more work on the client side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, easy decisions can become great enemies because we tend to overthink them. As a backend engineer, you'll face many decisions when building APIs. Whether it's handling webhooks, file uploading, or API versioning, there are advantages and disadvantages to each approach. By considering your specific use case and the tradeoffs involved, you can make informed decisions that lead to better APIs. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding ActiveRecord Nested Transactions</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Thu, 02 Jun 2022 19:27:23 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/understanding-activerecord-nested-transactions-3hee</link>
      <guid>https://dev.to/gerardosandoval/understanding-activerecord-nested-transactions-3hee</guid>
      <description>&lt;p&gt;As it reads in rails documentation -transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action.- You can take advantage of this behaviour to ensure that a number of statements are executed altogether or not at all.&lt;/p&gt;

&lt;p&gt;There is plenty of resources that talk about Transactions, but this one focuses only where it seems to lack clarification: &lt;em&gt;nested transactions&lt;/em&gt;. The official documentation on this topic can be confusing and because of that, here are some insights to fully understand how nested transactions behave and how to use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are nested transactions?
&lt;/h2&gt;

&lt;p&gt;Taking the simplest definition found online: - &lt;em&gt;A nested transaction is used to provide a transactional guarantee for a subset of operations performed within the scope of a bigger transaction. Doing this allows you to commit and abort the subset of operations independently of the larger transaction.&lt;/em&gt; -&lt;/p&gt;

&lt;p&gt;Most databases don't support true nested transactions and the only database that supports them is MS-SQL.&lt;/p&gt;

&lt;p&gt;In order to get around this problem, Rails transaction will emulate the effect of nested transactions, by using &lt;a href="https://dev.mysql.com/doc/refman/en/savepoint.html"&gt;&lt;em&gt;savepoints&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When are nested transaction required or used?
&lt;/h2&gt;

&lt;p&gt;Nested transactions can exist when we have models pointing to different databases. Each transaction evaluates and can create a single database connection, and rails does not distribute transactions across database connections, therefore, it is best if we nest transaction to imply the connection to different databases.&lt;/p&gt;

&lt;p&gt;Another example that I encounter the most is when we are working with external libraries or gems that process specific code inside a transaction which we can not fully control and in consequence we wrap around them with another transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  More on distributed transactions
&lt;/h2&gt;

&lt;p&gt;Quoting from rails source code: - &lt;em&gt;A transaction acts on a single database connection. If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:&lt;/em&gt; -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="c1"&gt;# https://github.com/rails/rails/blob/main/activerecord/lib/active_record/transactions.rb#L62&lt;/span&gt;

  &lt;span class="no"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;units&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;units&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;From the rails source code: - &lt;em&gt;This is a poor solution, but fully distributed transactions are beyond the scope of Active Record.&lt;/em&gt; - &lt;/p&gt;

&lt;h2&gt;
  
  
  How nested transactions behave?
&lt;/h2&gt;

&lt;p&gt;Nested transactions are intuitive and represent the normal transaction behaviour, if one statement fails, all fail. &lt;/p&gt;

&lt;p&gt;In detail, exceptions inside a transaction block will force a ROLLBACK that returns the database to the state before the transaction began and the exception will then be propagated to the parent transaction.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord::Rollback&lt;/code&gt; exception will trigger a database ROLLBACK when raised, but will not be re-raised by the transaction block and therefore will not be catched by the parent transaction. This exception is only meant to be used deliberately in exceptional situations.&lt;/p&gt;

&lt;p&gt;Transactions are meant to silently fail if &lt;code&gt;ActiveRecord::Rollback&lt;/code&gt; is raised inside the block, but if any other error is raised, the transactions will be rollbacked and the exception will be passed on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the documentation examples.
&lt;/h2&gt;

&lt;p&gt;Looking into the &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html"&gt;rails docs&lt;/a&gt; first example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Kotori'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Nemu'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Rollback&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;An &lt;code&gt;ActiveRecord::Rollback&lt;/code&gt; exception is being raised in the inner transaction, and therefore it should avoid the creation of the users, but as all database statements in the nested transaction block become part of the parent transaction and the &lt;code&gt;ActiveRecord::Rollback&lt;/code&gt; exception in the nested block does not carry up a ROLLBACK action to the parent transaction, both users are created. As I wrote before, ActiveRecord::Rollback exceptions will be intentionally rescued and swallowed without any consequences, and the parent transaction won't detect the exception.&lt;/p&gt;

&lt;p&gt;If we take the same example, but we raise a different exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Kotori'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Nemu'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&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;This will work as expected. The transactions are nested and joined correctly in only one connection (this is default behaviour), therefore, Nemu and Kotori won't be created. It also doesn't matter where the error is raised, if it is raised in the parent or child transactions it will still rollback all statements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating real nested sub-transactions
&lt;/h2&gt;

&lt;p&gt;We can achieve a different result by creating real sub-transaction by passing &lt;code&gt;requires_new: true&lt;/code&gt; to the inner transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Kotori'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;requires_new: &lt;/span&gt;&lt;span class="kp"&gt;true&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Nemu'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Rollback&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;This would treat each transaction separately and if an exception is raised in the inner transaction the database rolls back to the beginning of the sub-transaction without rolling back the parent transaction. Therefore the example above would only create the Kotori user.&lt;/p&gt;

&lt;p&gt;The documentation also gives just a bit of information about the 2 options that we can pass to the transaction method: &lt;em&gt;joinable&lt;/em&gt; and &lt;em&gt;requires_new&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This options help us treat nested transactions as individual database connections and therefore avoid dependancy between parent-childs transactions, also when intentionally raising an &lt;code&gt;ActiveRecord::Rollback&lt;/code&gt; exception. Each option is intended to be used depending on the nested hierarchy level of the transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;joinable:&lt;/strong&gt; default &lt;code&gt;true&lt;/code&gt;. Allows us to tell the outer transaction if we want the inner transaction to be joined within the same connection. If this value is set to &lt;code&gt;false&lt;/code&gt; and the inner transaction raises an exception it wont affect the outer transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;joinable: &lt;/span&gt;&lt;span class="kp"&gt;false&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Kotori'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# child transaction result wont affect the parent transaction&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Nemu'&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;&lt;strong&gt;requires_new:&lt;/strong&gt; default &lt;code&gt;nil&lt;/code&gt;. Allows us to tell the inner transaction if we want it to run in a different connection. If this value is set to &lt;code&gt;true&lt;/code&gt; and an exception is raised, it wont affect the parent transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Kotori'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# next transaction result wont affect the parent transaction&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;requires_new: &lt;/span&gt;&lt;span class="kp"&gt;true&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'Nemu'&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;So, this two options are meant to be used to run transactions in individual database connections depending on the nested hierarchy that you can control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html"&gt;https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.mysql.com/doc/refman/en/savepoint.html"&gt;https://dev.mysql.com/doc/refman/en/savepoint.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dotnettutorials.net/lesson/sql-server-savepoints-transaction/"&gt;https://dotnettutorials.net/lesson/sql-server-savepoints-transaction/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>activerecord</category>
      <category>transaction</category>
    </item>
    <item>
      <title>Avoid code oversimplification with RoR</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Tue, 09 Mar 2021 05:44:23 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/avoid-code-oversimplification-with-ror-gek</link>
      <guid>https://dev.to/gerardosandoval/avoid-code-oversimplification-with-ror-gek</guid>
      <description>&lt;p&gt;Through my years of working with Ruby on Rails, I've seen some common practices that I believe are not required and add complexity to the code base. &lt;/p&gt;

&lt;p&gt;This really simple practices look like they do no harm, but can make code less readable, add verbosity and insert unnecessary code.  &lt;/p&gt;

&lt;h2&gt;
  
  
  One expression methods
&lt;/h2&gt;

&lt;p&gt;Methods are supposed to encapsulate a set of processes or expressions, but sometimes they are wrongly used to define a single logic unit. Most of the time, developers create this methods to make the code more readable.&lt;/p&gt;

&lt;p&gt;Consider the next example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="ss"&gt;before_save: &lt;/span&gt;&lt;span class="n"&gt;setup_user&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_user&lt;/span&gt;
    &lt;span class="n"&gt;update_complexity&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_complexity&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&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;After looking at the example above, think about why should we separate the logic in two different methods when we can just move the assignation inside of the &lt;code&gt;setup_user&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_user&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first example is easier to read for the most of us, but it adds complexity to the model by adding one more method that is just redirecting to another one without doing anything else.&lt;/p&gt;

&lt;p&gt;The second example is readable enough to quickly understand the code intentions and keeps the model clean.&lt;/p&gt;

&lt;p&gt;Devs should always account for readability but also keep complexity in mind, it is easier to read a one line raw statement instead of dealing with fat models.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Prefixing the model name when naming methods, variables and constants
&lt;/h2&gt;

&lt;p&gt;Naming variables, constants and methods can be such a basic but painful thing to do, the name you choose is not always understandable enough for others. It is not great also when names mean more that they should. &lt;/p&gt;

&lt;p&gt;See the next example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="no"&gt;USER_DEFAULT_ROLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;
  &lt;span class="o"&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;In the example above we define the user's default role as a constant, we are being very specific in the name so we know that the default role belongs to the user model, but... why?&lt;/p&gt;

&lt;p&gt;If we call this constant from outside the scope of the model, we would call it like this &lt;code&gt;User::USER_DEFAULT_ROLE&lt;/code&gt;, and as you can see, we are repeating the word "User". It may not look like it can affect the readability of the code, but imagine having several constants in the same model or just having long model and constant names...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompanyConciliationFee&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="no"&gt;COMPANY_CONCILIATION_FEE_DEVELOPMENT_COST_RATIO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.59&lt;/span&gt;
  &lt;span class="o"&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;Look at how long it would look if we call this invented constant from outside the model scope!&lt;br&gt;
&lt;code&gt;MaintenanceFee::COMPANY_CONCILIATION_FEE_DEVELOPMENT_COST_RATIO&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Yeah, the example might look like I wrote the first thing that came to my mind... but that's basically how naming works.&lt;/p&gt;

&lt;p&gt;Another reason people do this is because they are thinking to use the constant within the scope of the model, where it wouldn't need to prefix the class name. This may be more straightforward but remember that all constants are always associated to the model they are defined into.&lt;/p&gt;

&lt;p&gt;Prefixing the model or class can happen with constants, variables and methods, and even when they feel necessary, keep in mind that they will clutter your code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Endless class reference
&lt;/h2&gt;

&lt;p&gt;Endless class reference refers to something similar to &lt;em&gt;one expression methods&lt;/em&gt; but through classes.&lt;/p&gt;

&lt;p&gt;Sometimes we break down the code structure to what we think are the necessary classes to get the job done, I.E. services, presenters, PORO's or whatever type of code encapsulation we can use, but sometimes we lengthen the logic by using more than we need, and therefore increase complexity.&lt;/p&gt;

&lt;p&gt;Look at the next example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserGenerator&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&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;...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="no"&gt;UserAvatarUploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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;avatar&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;avatar&lt;/span&gt;
  &lt;span class="o"&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;class&lt;/span&gt; &lt;span class="nc"&gt;UserAvatarUploader&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="no"&gt;AvatarUploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&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;avatar&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;class&lt;/span&gt; &lt;span class="nc"&gt;AvatarUploader&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;avatar: &lt;/span&gt;&lt;span class="n"&gt;avatar&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 follow the process to create a user and upload an avatar, you can observe that we are actually using 3 different services to do one simple thing, upload an avatar.&lt;/p&gt;

&lt;p&gt;This example is a very basic and simplified version of what happens in production code bases that are used by thousands of people every day. User's don't notice, but devs suffer when debugging only to find out that they have to follow an endless class reference to figure out where in the code the avatar is uploaded.&lt;/p&gt;

&lt;p&gt;We don't need all those classes. Keep it simple... if you only job is to upload an avatar, follow the KISS principle and keep it in only one service, you don't need the others! It may feel to you that you are decoupling service responsibilities, but what you are actually doing is making your jr. teammates life very unpleasant one. &lt;/p&gt;

&lt;p&gt;And there it was... a few cases that I often see in Ruby on Rails codebases that can be avoided. What do you think? Do you know about another common simple practice that can be avoided to simplify our code?&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>bestpractices</category>
      <category>complexity</category>
    </item>
    <item>
      <title>Minimal Net/HTTP client template</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Sun, 17 Jan 2021 21:35:55 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/minimal-net-http-client-template-4d96</link>
      <guid>https://dev.to/gerardosandoval/minimal-net-http-client-template-4d96</guid>
      <description>&lt;p&gt;Have you ever wanted to fetch information from an API and realize that there is no existent library or gem for that specific service?  &lt;/p&gt;

&lt;p&gt;If you find yourself in that situation and are planning to build your own client, you may already know that there are plenty of third party HTTP client libraries to use (Faraday, HTTParty, rest-client, etc.)... And yeah, without issues you can use any of those to build your client, but also you can achieve that with minimal effort using &lt;code&gt;Net::HTTP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Net::HTTP&lt;/code&gt; may not be the first option for most developers, its implementation is not the simplest or the easiest, but it definitely capable of building a robust client without the need of requiring additional code.&lt;/p&gt;

&lt;p&gt;Here's an example of a client built with &lt;code&gt;Net::HTTP&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
   Net::HTTP Client example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'net/http'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'uri'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;
  &lt;span class="no"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://api.example.com"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# set credentials or token if required&lt;/span&gt;
    &lt;span class="vi"&gt;@api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;
    &lt;span class="vi"&gt;@secret_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_key&lt;/span&gt;
    &lt;span class="vi"&gt;@api_uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;API_ENDPOINT&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;def&lt;/span&gt; &lt;span class="nf"&gt;get_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# additional request options defined by the API I.E. { page: 1, limit: 30 }&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;def&lt;/span&gt; &lt;span class="nf"&gt;post_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/create_user"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="c1"&gt;# User options that are required to create the user&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# execute and store the request response&lt;/span&gt;
    &lt;span class="vi"&gt;@response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# parse response&lt;/span&gt;
    &lt;span class="n"&gt;parsed_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# return the parsed response, otherwise raise an error&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parsed_response&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response_successful?&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;parsed_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;parsed_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Receives a valid Net::HTTP request object and data to set as the request body&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;use_ssl: &lt;/span&gt;&lt;span class="n"&gt;use_ssl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# Set headers&lt;/span&gt;
      &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;net_request&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;# Set request body from the data argument&lt;/span&gt;
      &lt;span class="n"&gt;net_request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; 
      &lt;span class="c1"&gt;# Execute the request &lt;/span&gt;
      &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_request&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="nf"&gt;headers&lt;/span&gt;
    &lt;span class="c1"&gt;# define headers here&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s1"&gt;'Authorization'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;auth token or keys&amp;gt;,&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;response_successful?&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'200'&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;h5&gt;
  
  
  Usage
&lt;/h5&gt;

&lt;p&gt;The client usage is very simple, just initialize the client, call the specific request method and pass the required options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;api_credentials&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;page: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;limit: &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Adding more request endpoints
&lt;/h5&gt;

&lt;p&gt;You just need to add a new method to the client with the specific &lt;code&gt;Net::HTTP&lt;/code&gt; request object and pass the parameters required by the API.&lt;/p&gt;

&lt;p&gt;That's it!... a simple &lt;code&gt;Net::HTTP&lt;/code&gt; client template for you to use.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>client</category>
      <category>http</category>
      <category>api</category>
    </item>
    <item>
      <title>Use your brain!</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Mon, 28 Dec 2020 20:44:00 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/use-your-brain-45l2</link>
      <guid>https://dev.to/gerardosandoval/use-your-brain-45l2</guid>
      <description>&lt;p&gt;The idea of programmers sole job is googling stuff has gained popularity over time, and it actually has a great amount of truth in it, but in order to be a great programmer, you need to absorbe the knowledge you google for, and that may not be as easy as it reads.&lt;/p&gt;

&lt;p&gt;Some programmers use google, stack-overflow or any other source to find insights on how to solve a problem, and most of them follow this as the first thing to do after a new issue has been assigned to them. But hey! Guess what? It shouldn't be!&lt;/p&gt;

&lt;p&gt;Your plan A or first thing to do should always be using your brain... Think first and search after (if needed).&lt;/p&gt;

&lt;p&gt;Plan B will be to google for some insights and/or maybe the answer. More times that not you'll be using the fallback plan (plan B), and thats OK, but always try to use the fallback plan after you apply plan A.&lt;/p&gt;

&lt;h5&gt;
  
  
  Two reasons of why you are not learning anything new:
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;If you don't put some effort on thinking solutions... Your brain will never be used to associate and remember this information.&lt;/li&gt;
&lt;li&gt;You are a lazy ass that avoids heavy thinking and prefers to google stuff out first.&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Tips:
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Think before googling!&lt;/li&gt;
&lt;li&gt;Read, analyze, implement, and if it works -&amp;gt; document.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Code review culture does matter</title>
      <dc:creator>Gerardo Sandoval</dc:creator>
      <pubDate>Mon, 28 Dec 2020 20:32:03 +0000</pubDate>
      <link>https://dev.to/gerardosandoval/code-review-culture-does-matter-3a8i</link>
      <guid>https://dev.to/gerardosandoval/code-review-culture-does-matter-3a8i</guid>
      <description>&lt;h1&gt;
  
  
  Code-Review culture does matter.
&lt;/h1&gt;

&lt;p&gt;Some time ago I found myself working for a company with great social and professional culture, working there felt great, but... it didn't last long.&lt;/p&gt;

&lt;p&gt;I realized that there were some organizational issues that were impacting greatly on the engineering team performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Definition of responsibilities was lacking&lt;/li&gt;
&lt;li&gt;Devs were mainly working alone with poor team communication&lt;/li&gt;
&lt;li&gt;Only few development standards and practices were set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Among those issues, I was always struggling with an specific problem: getting my PR's reviewed, approved and merged.&lt;/p&gt;

&lt;p&gt;Deliverance was so slow that some PR's were stuck in the &lt;em&gt;in review&lt;/em&gt; column for more than a month, those developments were a lost couse, outdated and with several conflicts, more work was needed to update them that the work needed to develop them in the first place.&lt;/p&gt;

&lt;p&gt;I found myself working in a startup with a very poor code-review culture.&lt;/p&gt;

&lt;p&gt;After reading and investigating a while I found that there are some practices that can be adopted to strengthen your code review culture, boost deliverance and build a better team. The next practices are based on a talk by Derek Prior &lt;a href="https://www.youtube.com/watch?v=PJjmw9TRB7s"&gt;(link)&lt;/a&gt; and some other readings.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿How to prepare for and improve your code review culture?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;As a team, decide your process and what to expect of reviews and make responsibilities clear:

&lt;ul&gt;
&lt;li&gt;Number of reviews before merging&lt;/li&gt;
&lt;li&gt;Who can merge?&lt;/li&gt;
&lt;li&gt;Can I merge my own PR?&lt;/li&gt;
&lt;li&gt;How should I ask for review?&lt;/li&gt;
&lt;li&gt;Who and why should be reviewing my code?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Take in mind that code review does not include QA&lt;/li&gt;
&lt;li&gt;Adopt a styleguide and outsource it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿What are the benefits of a strong code review culture?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Better code - quality discussions improve code quality&lt;/li&gt;
&lt;li&gt;Better developers - Conflict are good for learning, in a healthy way&lt;/li&gt;
&lt;li&gt;Team ownership - Remove modular dependencies and win developer's versatility&lt;/li&gt;
&lt;li&gt;Healthy debate - More meaningful technical discussions in a proactive culture&lt;/li&gt;
&lt;li&gt;A better place to work&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rules of Engagement
&lt;/h3&gt;

&lt;h5&gt;
  
  
  ¿What to do as an author?
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Provide sufficient context. Explain your changes and avoid context hunting. &lt;em&gt;If content is king, then context is God (Gary Vaynerchuk).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Explain why you chose that solutions, not everyone thinks like you.&lt;/li&gt;
&lt;li&gt;¿You learned something new and useful? Document it! It can help others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  ¿What to do as a reviewer?
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Ask, don't tell. Write your observations as a question instead of demanding a change. Asking the right questions the right way results in a better technical discussion.&lt;/li&gt;
&lt;li&gt;Offer compliments and be positive. Comment the code that you find useful and of quality with a compliment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  In practice
&lt;/h3&gt;

&lt;h5&gt;
  
  
  ¿How to handle disagreements?
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Agree to disagree. There's different ways to get things done.&lt;/li&gt;
&lt;li&gt;Create a discussion and be open to new alternatives. If you don’t know which is better, ask.&lt;/li&gt;
&lt;li&gt;Ask for a tie breaker opinion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  ¿What should I be reviewing anyway?
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Single responsibility principle&lt;/li&gt;
&lt;li&gt;Naming, easier to understand and discuss&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Test Coverage&lt;/li&gt;
&lt;li&gt;Look for bugs involving your area of expertise&lt;/li&gt;
&lt;/ul&gt;




&lt;h6&gt;
  
  
  Interested? Read these articles for more tips and information:
&lt;/h6&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=PJjmw9TRB7s"&gt;https://www.youtube.com/watch?v=PJjmw9TRB7s&lt;/a&gt;&lt;br&gt;
&lt;a href="https://thoughtbot.com/blog/five-tips-for-more-helpful-code-reviews"&gt;https://thoughtbot.com/blog/five-tips-for-more-helpful-code-reviews&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chelseatroy.com/2019/12/18/reviewing-pull-requests/"&gt;https://chelseatroy.com/2019/12/18/reviewing-pull-requests/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>deliverance</category>
    </item>
  </channel>
</rss>
