<?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: Ernesto Tagwerker (he/him)</title>
    <description>The latest articles on DEV Community by Ernesto Tagwerker (he/him) (@etagwerker).</description>
    <link>https://dev.to/etagwerker</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%2F69379%2F614aefdc-d82c-47eb-ba89-134cfa351a69.jpeg</url>
      <title>DEV Community: Ernesto Tagwerker (he/him)</title>
      <link>https://dev.to/etagwerker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/etagwerker"/>
    <language>en</language>
    <item>
      <title>Fortify Rails - Defending Your Ruby on Rails Applications from Bad Actors</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Mon, 26 Jun 2023 12:34:56 +0000</pubDate>
      <link>https://dev.to/fastruby/fortify-rails-defending-your-ruby-on-rails-applications-from-bad-actors-25j2</link>
      <guid>https://dev.to/fastruby/fortify-rails-defending-your-ruby-on-rails-applications-from-bad-actors-25j2</guid>
      <description>&lt;p&gt;On Monday June 12th, 2023, FastRuby.io partnered with &lt;a href="https://expeditedsecurity.com/"&gt;Expedited Security&lt;/a&gt; to talk about how to secure your Ruby on Rails application.&lt;/p&gt;

&lt;p&gt;In this free webinar &lt;a href="https://mastodon.social/@etagwerker"&gt;Ernesto Tagwerker&lt;/a&gt; (FastRuby.io) and &lt;a href="https://ruby.social/@mbuckbee"&gt;Mike Buckbee&lt;/a&gt; (Expedited Security) discussed topics of interest related to &lt;a href="https://fastruby.io/blog/tags/security"&gt;Rails security&lt;/a&gt; (exploitable ActiveRecord code, vulnerable dependencies, botnets, DDoS, a breakdown of common threats, and more).&lt;/p&gt;

&lt;p&gt;You’ll also get a sneak peak of &lt;a href="https://wafris.org/"&gt;Wafris&lt;/a&gt;, an Open Source service to prevent attackers and dark traffic to your application and of our new &lt;a href="https://www.fastruby.io/security-audit?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=webinar"&gt;Rails Security Audit&lt;/a&gt;, a service to detect vulnerabilities and exploitable code in your app!&lt;/p&gt;

&lt;p&gt;Check out the recording of the Fortify Rails webinar here: &lt;a href="https://www.youtube.com/embed/KkXTw7UDR9w"&gt;https://www.youtube.com/embed/KkXTw7UDR9w&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the slides on exploitable code and insecure dependencies: &lt;a href="https://speakerdeck.com/etagwerker/fortify-rails-webinar"&gt;https://speakerdeck.com/etagwerker/fortify-rails-webinar&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to read more about Ruby and Rails security tooling check out this article: &lt;a href="https://www.fastruby.io/blog/rails/security/ruby-security-toolkit.html"&gt;4 Essential Security Tools To Level Up Your Rails Security&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Need a trusted third party to give you a prioritized list of security issues? Check out our &lt;a href="https://www.fastruby.io/security-audit?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=webinar"&gt;Rails Security Audit&lt;/a&gt; service. &lt;/p&gt;

</description>
      <category>rails</category>
      <category>security</category>
    </item>
    <item>
      <title>Power Home Remodeling Increases Server Speed by 40% with FastRuby.io’s Tune Report</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Fri, 02 Jun 2023 10:10:59 +0000</pubDate>
      <link>https://dev.to/fastruby/power-home-remodeling-increases-server-speed-by-40-with-fastrubyios-tune-report-3e02</link>
      <guid>https://dev.to/fastruby/power-home-remodeling-increases-server-speed-by-40-with-fastrubyios-tune-report-3e02</guid>
      <description>&lt;p&gt;&lt;a href="https://powerhrg.com/"&gt;Power Home Remodeling (Power)&lt;/a&gt; is the nation’s largest full-service exterior home remodeler and a top workplace.&lt;/p&gt;

&lt;p&gt;Headquartered in Chester, Pennsylvania with offices in 18 territories across the United States, the award-winning company’s primary product line includes windows, siding, doors, roofing, solar roofing panels, and attic insulation.&lt;/p&gt;

&lt;p&gt;In this article we will share how our &lt;a href="https://fastruby.io/tune"&gt;Tune Report&lt;/a&gt;  helped Power speed up their application by reducing their average page load time from 5 to 3 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Challenge
&lt;/h2&gt;

&lt;p&gt;Power provides homeowners with top-rated customer service, and quality, energy-efficient products that help upgrade their home’s exterior. While a home remodeling company at its core, Power has also become a leader in workplace culture, leadership development, and technology.&lt;/p&gt;

&lt;p&gt;Behind the scenes, Power’s unique, state-of-the-art collaborative intelligence platform—known as Nitro—enables seamless, real-time communication across the business.&lt;/p&gt;

&lt;p&gt;The company’s technologists are responsible for developing and delivering Nitro’s software through continuous integration, as well as the three data centers that manage it.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://www.linkedin.com/in/wadewinningham"&gt;Wade Winningham&lt;/a&gt;, Principal Developer, “We don’t use third-party applications for our sales, lead generation, tracking, and fulfillment. We’ve built everything ourselves and we’re proud that we operate our own platforms and technology without much reliance on an outside cloud.”&lt;/p&gt;

&lt;p&gt;Wade, who helps set standards for the entire department, is always on the alert for ways to enhance and refresh their technology infrastructure. For the past six years, they have reached out to us anytime they needed support with Ruby on Rails maintenance, development, and &lt;a href="https://fastruby.io/blog/tags/upgrades"&gt;upgrades&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Several years ago, the Ruby on Rails version underlying Power’s software was getting stale, but due to the size of their application, it was going to be a daunting task to handle internally.&lt;/p&gt;

&lt;p&gt;We were hired to help with the &lt;a href="https://fastruby.io/blog/rails/upgrades/upgrade-rails-from-3-2-to-4-0.html"&gt;upgrade from Rails 3.2 to 4.0&lt;/a&gt;. “&lt;a href="https://www.ombulabs.com"&gt;OmbuLabs&lt;/a&gt;/FastRuby.io is an expert in Ruby and Rails, and we knew it was going to be in our best interest to hire them,” explained Wade.&lt;/p&gt;

&lt;p&gt;“&lt;a href="https://www.fastruby.io/blog/rails/upgrades/case-study/upgrading-a-monolith.html"&gt;The Rails upgrade project was a huge success&lt;/a&gt;. The developers were top notch, knew what they were doing, understood our internal application, and helped us through it.” We collaborated with Power’s team to get them all the way to Rails 6.0 and then they continued their upgrade journey.&lt;/p&gt;

&lt;p&gt;Our next challenge was to find ways for our clients to identify optimization opportunities within their Rails applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Tune Report
&lt;/h2&gt;

&lt;p&gt;Recently, in partnership with &lt;a href="https://www.nateberkopec.com/"&gt;Nate Berkopec&lt;/a&gt; from &lt;a href="https://www.speedshop.co/"&gt;Speedshop&lt;/a&gt;, we launched our new &lt;a href="https://fastruby.io/tune"&gt;Tune Report&lt;/a&gt;, which helps our clients accelerate their Ruby applications, reach &lt;a href="https://fastruby.io/blog/tags/performance"&gt;a higher level of performance&lt;/a&gt;, and reduce server costs.&lt;/p&gt;

&lt;p&gt;We shared our new service with Wade and his team, and they immediately saw the benefits. “We thought it would be great to have an outside perspective of our application. The Tune Report would look at areas that we weren’t focusing on or even aware of having potential issues.”&lt;/p&gt;

&lt;h3&gt;
  
  
  See the results:
&lt;/h3&gt;

&lt;p&gt;Our first step was to meet with everyone involved. The business technology team provided access to their repositories, internal hardware statistics, application metrics, and codebase to monitor and observe the application.&lt;/p&gt;

&lt;p&gt;After we had a chance to explore, read, and analyze the source code, we delivered our Tune Report, which provided a list of key areas that could be immediately addressed and others that could be improved upon over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doing More with Less: Improved Server Performance Results in Reduced Costs
&lt;/h3&gt;

&lt;p&gt;Power’s applications run in a containerized environment. Their theory was that if they had more server instances and fewer processes running in those servers spread out over a wide area, that their application would be more resilient.&lt;/p&gt;

&lt;p&gt;However, our Tune Report revealed an excessive amount of memory available, compared to the amount of CPU they were able to use within their servers.&lt;/p&gt;

&lt;p&gt;Our recommendation was to reduce the number of server instances and increase the number of processes that each server executed.&lt;/p&gt;

&lt;p&gt;For example, instead of having 60 servers with 2 processes, it would be far more efficient to have 20 servers with 6 to 8 processes each.&lt;/p&gt;

&lt;p&gt;With more processes per server, there is less chance of one of those being busy when a request arrives. By making this adjustment, we were able to drive down the wait time from an average of 20-50 milliseconds to almost 0 milliseconds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With this, and all other changes made so far from the report, page loads were reduced from 5 seconds to below 3 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“This was a huge win for us because we were able to size our application accordingly across multiple server instances,” said Wade. “It only took a few days to test this and verify that they were right.”&lt;/p&gt;

&lt;p&gt;By running fewer server instances, hardware is freed up and computational power can be reallocated; ultimately, this results in cost savings and increased speed using half the server capacity.&lt;/p&gt;

&lt;p&gt;We also found ways to improve query performance by adding indexes in the database. “These were simple for us to add and immediately improved performance across our application,” said Wade.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Importance of Regular Checkups
&lt;/h3&gt;

&lt;p&gt;For Wade, the &lt;a href="https://fastruby.io/tune"&gt;Tune Report&lt;/a&gt; was like another set of eyes on areas they may not have thought to look at.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It was great to have OmbuLabs/FastRuby.io’ insights. They came in, showed us where we could make improvements, and it was easy to implement their suggestions.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our team delivered a report that enabled Power to show noticeable results to non-technical stakeholders:&lt;/p&gt;

&lt;p&gt;“Our executives were thrilled with the report,” shared Wade. “They liked the fact that we could take action immediately to experience an almost instantaneous impact, and recommended that we invest in a Tune Report on a regular basis.”&lt;/p&gt;

&lt;p&gt;Wade felt the Tune Report was well worth the time and effort of getting an outside perspective and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I was shocked that we were able to do so much in a short amount of time and to show that kind of return on investment. The Tune Report came at a really great time and showed us how beneficial it was to do—not just once, but routinely. It’s like taking your application to the auto mechanic for a checkup.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“I really enjoy working with OmbuLabs/FastRuby.io. They’re experts at what they do, and I’ve always been impressed with their skill, professionalism, and knowledge,” concluded Wade. “They are also very involved in the Ruby community which just adds to their credibility.”&lt;/p&gt;

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

&lt;p&gt;The collaboration between Power and OmbuLabs/FastRuby.io exemplifies how external experts can bolster in-house technological capabilities. The Tune Report proved an invaluable resource in optimizing Power’s Nitro platform, leading to improved performance and cost savings.&lt;/p&gt;

&lt;p&gt;The success of this collaboration underscores the importance of &lt;a href="https://fastruby.io/tune"&gt;regular performance audits&lt;/a&gt; and the value they bring in terms of enhancing user experience, reducing costs, and maintaining a competitive edge in a technology-driven world.&lt;/p&gt;

&lt;p&gt;The Tune Report, product of a collaboration between FastRuby.io and Speedshop, proved instrumental in identifying optimization opportunities, leading to a significant decrease in average page load time, from 5 to 3 seconds.&lt;/p&gt;

&lt;p&gt;One of the key recommendations, reducing the number of server instances and increasing the number of processes per server, resulted in a drop in wait time from 20-50 milliseconds to almost 0.&lt;/p&gt;

&lt;p&gt;If you are interested in hearing more about our &lt;a href="https://fastruby.io/tune"&gt;Ruby/Rails performance audits&lt;/a&gt;, &lt;a href="https://www.fastruby.io/tune#contactus"&gt;send us a quick message&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  WHO WE ARE:
&lt;/h3&gt;

&lt;p&gt;OmbuLabs is &lt;a href="https://www.ombulabs.com"&gt;Philadelphia's lean software boutique&lt;/a&gt;. Specializing in Ruby, &lt;a href="https://www.fastruby.io"&gt;Ruby/Rails Upgrades&lt;/a&gt; (FastRuby.io), JavaScript, &lt;a href="https://www.upgradejs.com"&gt;JavaScript Upgrades&lt;/a&gt; (UpgradeJS.com), minimum viable product development, and reducing technical debt, we help companies (from startups to Fortune 500 companies) build and improve their digital products.&lt;/p&gt;

&lt;p&gt;Founded in 2011 and headquartered in Philadelphia, Pennsylvania, our experienced and diverse team of developers is ready to do whatever it takes to help your business grow. &lt;/p&gt;

&lt;p&gt;To learn more, visit us at &lt;a href="https://www.ombulabs.com"&gt;OmbuLabs.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>performance</category>
    </item>
    <item>
      <title>4 Essential Security Tools To Level Up Your Rails Security</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Wed, 31 May 2023 11:23:45 +0000</pubDate>
      <link>https://dev.to/fastruby/4-essential-security-tools-to-level-up-your-rails-security-4ffe</link>
      <guid>https://dev.to/fastruby/4-essential-security-tools-to-level-up-your-rails-security-4ffe</guid>
      <description>&lt;p&gt;At FastRuby.io we love &lt;a href="https://rubyonrails.org" rel="noopener noreferrer"&gt;Ruby on Rails&lt;/a&gt; because it is so powerful: You can quickly create an application that is feature complete, stable, and &lt;a href="https://guides.rubyonrails.org/security.html" rel="noopener noreferrer"&gt;secure&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, maintaining a Rails application up to date and secure takes some effort.&lt;/p&gt;

&lt;p&gt;In this blog post, we will cover a few Ruby gems and best practices that you can use to stay on top of your security, reliability, and stability needs.&lt;/p&gt;

&lt;p&gt;Before we dive into 4 different Ruby gems you can use to improve your security support, let’s start with some of the security goodies that already come with Rails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails’ Native Security Features
&lt;/h2&gt;

&lt;p&gt;The good news is that Rails comes with a ton of security support, here are a few features that you are probably already using in your application:&lt;/p&gt;

&lt;h3&gt;
  
  
  Forcing SSL
&lt;/h3&gt;

&lt;p&gt;You can easily secure your authentication by enabling TLS in your configuration:&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;# config/environments/production.rb&lt;/span&gt;
&lt;span class="c1"&gt;# Force all access to the app over SSL,&lt;/span&gt;
&lt;span class="c1"&gt;# use Strict-Transport-Security,&lt;/span&gt;
&lt;span class="c1"&gt;# and use secure cookies&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;force_ssl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If your web server (e.g. nginx) doesn’t force SSL, your Rails application will.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSRF (Cross Site Request Forgery)
&lt;/h3&gt;

&lt;p&gt;Some of these security features are enabled by default. For instance: &lt;a href="https://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf" rel="noopener noreferrer"&gt;CSRF&lt;/a&gt;. Ruby on Rails has specific, built-in support for CSRF tokens.&lt;/p&gt;

&lt;p&gt;If you see this line in your &lt;code&gt;application_controller.rb&lt;/code&gt;, you know that you are including Rails’ protection against cross site request forgery:&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;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;protect_from_forgery&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  CORS (Cross Origin Resource Sharing)
&lt;/h3&gt;

&lt;p&gt;Occasionally, a need arises to share resources with another domain. For example, a file-upload function that sends data via an AJAX request to another domain.&lt;/p&gt;

&lt;p&gt;In these cases, the same-origin rules followed by web browsers must be sent. Modern browsers, in compliance with HTML5 standards, will allow this to occur but in order to do this; some precaution must be taken.&lt;/p&gt;

&lt;p&gt;For this, you can use the &lt;a href="https://github.com/cyu/rack-cors" rel="noopener noreferrer"&gt;&lt;code&gt;rack-cors&lt;/code&gt;&lt;/a&gt; gem:&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;gem&lt;/span&gt; &lt;span class="s1"&gt;'rack-cors'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'rack/cors'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You can configure it as a middleware like this:&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;# config/application.rb:&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Sample&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cors&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;origins&lt;/span&gt; &lt;span class="s1"&gt;'audit.fastruby.io'&lt;/span&gt;
        &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="sr"&gt;%r{/users/&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;+.json}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;:headers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Origin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Accept'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;:methods&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;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get&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;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;
  
  
  Filtering Parameters
&lt;/h3&gt;

&lt;p&gt;To make sure sensitive request parameters aren’t logged to your log files, you can set up your application like this:&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;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_parameters&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="ss"&gt;:credit_card_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:social_security_number&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Values for these parameters will now show up as &lt;code&gt;"[FILTERED]"&lt;/code&gt; in your log files.&lt;/p&gt;

&lt;p&gt;Now that we have covered some of the &lt;strong&gt;key security features in Rails&lt;/strong&gt; , let’s look at &lt;strong&gt;4 gems&lt;/strong&gt; that can help you level up your security best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bundler Audit&lt;/li&gt;
&lt;li&gt;Brakeman&lt;/li&gt;
&lt;li&gt;Rack::Attack&lt;/li&gt;
&lt;li&gt;Secure Headers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bundler Audit
&lt;/h2&gt;

&lt;p&gt;This Ruby gem is quite useful for detecting versions of gems that are known to be vulnerable to security issues. &lt;a href="https://github.com/rubysec/bundler-audit" rel="noopener noreferrer"&gt;&lt;code&gt;bundler-audit&lt;/code&gt;&lt;/a&gt; uses an open database of vulnerable gems called &lt;a href="https://github.com/rubysec/ruby-advisory-db" rel="noopener noreferrer"&gt;&lt;code&gt;ruby-advisory-db&lt;/code&gt;&lt;/a&gt; and compares it to the versions that show up in your &lt;code&gt;Gemfile.lock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can install it and run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler-audit
bundle-audit

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

&lt;/div&gt;



&lt;p&gt;If there are vulnerable versions in your &lt;code&gt;Gemfile.lock&lt;/code&gt; it will show you something like this:&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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Fbundle-audit-output-screenshot.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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Fbundle-audit-output-screenshot.png" alt="bundle-audit output for an app that has vulnerable dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything looks good, it will show you something like this:&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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Fbundle-audit-no-vulnerabilities.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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Fbundle-audit-no-vulnerabilities.png" alt="bundle-audit output for an app that has no vulnerable dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few years ago we built a small, open source, web application to make it easier for us to share these vulnerabilities reports with our clients. You can find it and use it over here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://audit.fastruby.io" rel="noopener noreferrer"&gt;Bundler Audit Tool&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It usually looks like this:&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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Faudit-fastruby-io-screenshot.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%2Ffastruby.io%2Fblog%2Fassets%2Fimages%2Faudit-fastruby-io-screenshot.png" alt="bundle-audit results in the open source application hosted by FastRuby.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bundler-audit&lt;/code&gt; relies on &lt;code&gt;ruby-advisory-db&lt;/code&gt;, a community-maintained database of known security vulnerabilities. While this is a great approach, it may also lead to gaps in coverage if a vulnerability is not yet documented in the database or if the database becomes outdated.&lt;/p&gt;

&lt;p&gt;If you want to make sure that &lt;code&gt;bundler-audit&lt;/code&gt; is running with the latest version of the &lt;code&gt;ruby-advisory-db&lt;/code&gt;, you should always call it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle-audit check --update

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Brakeman
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://brakemanscanner.org/" rel="noopener noreferrer"&gt;&lt;code&gt;brakeman&lt;/code&gt;&lt;/a&gt; is another useful Ruby gem that is a static analysis security vulnerability scanner for Ruby on Rails applications.&lt;/p&gt;

&lt;p&gt;You can quickly run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd path/to/rails-app
gem install brakeman
brakeman

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

&lt;/div&gt;



&lt;p&gt;This will run a battery of “checks” against your source code and report any potential security issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loading scanner...
Processing application in /Users/etagwerker/Projects/ombulabs/foobar
Processing gems...
[Notice] Detected Rails 6 application
Processing configuration...
[Notice] Escaping HTML by default
Parsing files...
Detecting file types...
Processing initializers...
Processing libs...
Processing routes...
Processing templates...
Processing data flow in templates...
Processing models...
Processing controllers...
Processing data flow in controllers...
Indexing call sites...
Running checks in parallel...
 - CheckBasicAuth
 ...
 - CheckYAMLParsing
Checks finished, collecting results...
Generating report...

== Brakeman Report ==

Application Path: /Users/etagwerker/Projects/ombulabs/foobar
Rails Version: 6.1.4
Brakeman Version: 5.4.1
Scan Date: 2023-05-02 15:18:55 -0400
Duration: 0.430032 seconds
Checks Run: BasicAuth, ..., YAMLParsing

== Overview ==

Controllers: 3
Models: 2
Templates: 15
Errors: 0
Security Warnings: 2

== Warning Types ==

Cross-Site Scripting: 1
Unmaintained Dependency: 1

== Warnings ==

Confidence: High
Category: Unmaintained Dependency
Check: EOLRuby
Message: Support for Ruby 2.7.2 ended on 2023-03-31
File: .ruby-version
Line: 1

Confidence: Weak
Category: Cross-Site Scripting
Check: SanitizeConfigCve
Message: rails-html-sanitizer 1.3.0 is vulnerable to cross-site scripting when `select` and `style` tags are allowed (CVE-2022-32209). Upgrade to 1.4.3 or newer
File: Gemfile.lock
Line: 194

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

&lt;/div&gt;



&lt;p&gt;To see a complete list of checks ran by Brakeman, you can find them over here: &lt;a href="https://github.com/presidentbeef/brakeman/tree/main/lib/brakeman/checks" rel="noopener noreferrer"&gt;List of Brakeman Checks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sample application is in pretty good shape, but it does report two warnings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;High: I’m using Rails 6.1 with Ruby 2.7.2. &lt;a href="https://twitter.com/yukihiro_matz/status/1639758019235053571" rel="noopener noreferrer"&gt;Security support for Ruby 2.7.x ended on March 31st, 2023&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Weak: I’m using a version of &lt;a href="https://rubygems.org/gems/rails-html-sanitizer" rel="noopener noreferrer"&gt;&lt;code&gt;rails-html-sanitizer&lt;/code&gt;&lt;/a&gt; that is known to be vulnerable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of them is quite easy to fix: &lt;code&gt;bundle update rails-html-sanitizer&lt;/code&gt; and the warning goes away. We can safely deploy this to production with a small pull request.&lt;/p&gt;

&lt;p&gt;The other warning might be harder to accomplish: We need to &lt;a href="https://www.fastruby.io/blog/ruby/upgrades/upgrade-ruby-from-2.7-to-3.0.html" rel="noopener noreferrer"&gt;upgrade from Ruby 2.7 to 3.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just like any other static analysis tool, &lt;code&gt;brakeman&lt;/code&gt; may generate false positives or negatives. This means that it might report issues that aren’t actually problems or fail to detect actual vulnerabilities. We need to be cautious when interpreting the results and not rely solely on these tools for ensuring security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rack::Attack
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rack-attack&lt;/code&gt; is a middleware that can be used in your Rails application (and any rack-based Ruby applications!) to protect it from &lt;em&gt;bad clients&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Rack::Attack&lt;/code&gt; lets you easily decide when to allow, block and throttle based on properties of the request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are some of its key features:&lt;/p&gt;

&lt;h3&gt;
  
  
  Safelisting / Blocklisting
&lt;/h3&gt;

&lt;p&gt;You can quickly allow an IP like this:&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;# config/initializers/rack_attack.rb (for rails app)&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safelist_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"5.6.7.0/24"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This could be useful if you want to allowlist your development team’s IP addresses.&lt;/p&gt;

&lt;p&gt;You could quickly block an IP like this:&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;# config/initializers/rack_attack.rb (for rails apps)&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blocklist_ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"1.2.3.4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It’s a powerful combination to combine &lt;code&gt;rack-attack&lt;/code&gt; with environment variables like this:&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;# config/initializers/rack-attack.rb&lt;/span&gt;

&lt;span class="n"&gt;bad_ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"BLOCKLIST_IPS"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# to be blocked&lt;/span&gt;

&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blocklist&lt;/span&gt; &lt;span class="s2"&gt;"blocklist bad IP address"&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;req&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;bad_ips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;good_ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SAFELIST_IPS"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# to be safelisted&lt;/span&gt;

&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safelist&lt;/span&gt; &lt;span class="s2"&gt;"safelisted good IP address"&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;req&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;good_ips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip&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;
  
  
  Throttling
&lt;/h3&gt;

&lt;p&gt;This would be a good way to slow down an attacker who is trying to sign in to a user account using a &lt;a href="https://www.kaspersky.com/resource-center/definitions/brute-force-attack" rel="noopener noreferrer"&gt;brute force attack&lt;/a&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;# Throttle login attempts for a given email parameter to 6 reqs/minute&lt;/span&gt;
&lt;span class="c1"&gt;# Return the *normalized* email as a discriminator on POST /login requests&lt;/span&gt;
&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'limit logins per email'&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;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;period: &lt;/span&gt;&lt;span class="mi"&gt;60&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;req&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'/login'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post?&lt;/span&gt;
    &lt;span class="c1"&gt;# Normalize the email, using the same logic as your authentication process, to&lt;/span&gt;
    &lt;span class="c1"&gt;# protect against rate limit bypasses.&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;downcase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&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;Additionally, you could have a more broad criteria for limiting the number of requests per minute:&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;# config/initializers/rack_attack.rb (for rails apps)&lt;/span&gt;

&lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"requests by ip"&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;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;period: &lt;/span&gt;&lt;span class="mi"&gt;2&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;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Based on the IP of the user, this configuration would limit their rate to 5 requests every 2 seconds.&lt;/p&gt;

&lt;p&gt;You can combine &lt;code&gt;rack-attack&lt;/code&gt; and &lt;a href="https://www.cloudflare.com" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; as a good way to prevent &lt;a href="https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/" rel="noopener noreferrer"&gt;DDoS attacks&lt;/a&gt;. Just because you are using &lt;code&gt;rack-attack&lt;/code&gt;, it doesn’t mean that you should not use a tool like Cloudflare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Headers
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/github/secure_headers" rel="noopener noreferrer"&gt;&lt;code&gt;secure_headers&lt;/code&gt;&lt;/a&gt; gem will automatically apply several headers that are related to security. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content Security Policy (CSP)&lt;/strong&gt; - Helps detect/prevent XSS, mixed-content, and other classes of attack. Default value: &lt;code&gt;default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP Strict Transport Security (HSTS)&lt;/strong&gt; - Protects from SSLStrip/Firesheep attacks. Default value: &lt;code&gt;max-age=631138519&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X-Frame-Options (XFO)&lt;/strong&gt; - Prevents your content from being framed and potentially clickjacked. Default value: &lt;code&gt;sameorigin&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X-XSS-Protection&lt;/strong&gt; - Cross site scripting heuristic filter for IE/Chrome. Default value: &lt;code&gt;1; mode=block&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X-Content-Type-Options&lt;/strong&gt; - Prevent content type sniffing. Default value: &lt;code&gt;nosniff&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X-Download-Options&lt;/strong&gt; - Prevent file downloads opening. Default value: &lt;code&gt;noopen&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;X-Permitted-Cross-Domain-Policies&lt;/strong&gt; - Restrict Adobe Flash Player’s access to data. Default value: &lt;code&gt;none&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While &lt;code&gt;secure_headers&lt;/code&gt; provides sensible safe default settings, it is essential to tailor them to your application’s specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;p&gt;If you’re interested in reading more about securing your Rails applications, here is a list of useful resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Ruby_on_Rails_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP’s Ruby on Rails Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://groups.google.com/g/rubyonrails-security" rel="noopener noreferrer"&gt;Ruby on Rails Security Email List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/presidentbeef/brakeman" rel="noopener noreferrer"&gt;Brakeman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://groups.google.com/g/ruby-security-ann" rel="noopener noreferrer"&gt;Ruby Security Email List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rack/rack-attack" rel="noopener noreferrer"&gt;Rack::Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rubysec/bundler-audit" rel="noopener noreferrer"&gt;Bundler::Audit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wafris.org/guides/ultimate-guide-to-rack-attack" rel="noopener noreferrer"&gt;Ultimate Guide to Rack::Attack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pxlpnk/awesome-ruby-security" rel="noopener noreferrer"&gt;Awesome Ruby Security Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;While Rails provides a lot of security features, there are at least 4 ways to level up your application’s security with these great tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;bundler-audit&lt;/code&gt; to find dependencies that are known to have vulnerabilities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;brakeman&lt;/code&gt; to find idioms/calls that could be dangerous for your application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rack-attack&lt;/code&gt; to defend your application against bad, abusive clients&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secure_headers&lt;/code&gt; to quickly apply several security headers to all your responses&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This list is by no means exhaustive but it shows some of the key tools you can use to stay on top of potential security issues.&lt;/p&gt;

&lt;p&gt;Although tools like &lt;code&gt;bundler-audit&lt;/code&gt; and &lt;code&gt;brakeman&lt;/code&gt; are helpful in identifying potential vulnerabilities, &lt;strong&gt;they should not be solely relied upon&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As a team, you should define a &lt;strong&gt;comprehensive security strategy&lt;/strong&gt; which includes regular code audits, code reviews, and penetration testing.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

&lt;p&gt;PS: &lt;a href="https://fastruby.io" rel="noopener noreferrer"&gt;Need a code security audit? Contact us!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>security</category>
    </item>
    <item>
      <title>Introduction to Rails Engines</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Tue, 23 May 2023 18:58:06 +0000</pubDate>
      <link>https://dev.to/fastruby/introduction-to-rails-engines-4ilj</link>
      <guid>https://dev.to/fastruby/introduction-to-rails-engines-4ilj</guid>
      <description>&lt;p&gt;Rails Engines are an architectural pattern that can be used to modularize a Rails application. They are self-contained applications that can be mounted within a larger Rails application. In this post, we will dive into the world of Rails Engines and explore what they are, how to create them, how to use them, when to use them, and why they are important.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Rails Engines?
&lt;/h2&gt;

&lt;p&gt;Rails Engines are essentially mini-applications that can be plugged into a larger Rails application. They allow you to modularize your code and keep it separate from the core application. This makes it easier to maintain and update the codebase as a whole.&lt;/p&gt;

&lt;p&gt;Engines can include models, controllers, views, and assets, and they can also have their own routes and configurations. For example &lt;a href="https://github.com/plataformatec/devise"&gt;Devise&lt;/a&gt;, an engine that provides authentication for a host application, has its own views, controllers, routes and configurations.&lt;/p&gt;

&lt;p&gt;It is worth mentioning that Rails Engines are similar to &lt;a href="https://api.rubyonrails.org/classes/Rails/Railtie.html"&gt;Railities&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, they differ in that Railities are simple Ruby modules that includes various hooks into the Rails initialization process, such as configuring middleware or adding new generators, whereas a Rails Engine has a more complex directory structure and includes everything needed to function as a standalone application, such as controllers, models, and views.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create a Rails Engine
&lt;/h2&gt;

&lt;p&gt;Creating a Rails engine is a relatively simple process. To create a new engine, run the following command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails plugin new payments --mountable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new Rails engine in the &lt;code&gt;payments&lt;/code&gt; directory with the &lt;code&gt;--mountable&lt;/code&gt; option, which means that the engine can be mounted within another Rails application. Please note that the &lt;code&gt;--mountable&lt;/code&gt; option is very important as running the above command without it will create a typical plugin which is not mountable. Below are the files generated by the above command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bin/rails plugin new payments --mountable
      create  
      create README.md
      create Rakefile
      create payments.gemspec
      create .gitignore
      create Gemfile
         run git init from "."
Initialized empty Git repository in /ombulabs.com/payments/.git/
      create app
      create app/controllers/payments/application_controller.rb
      create app/helpers/payments/application_helper.rb
      create app/jobs/payments/application_job.rb
      create app/mailers/payments/application_mailer.rb
      create app/models/payments/application_record.rb
      create app/views/layouts/payments/application.html.erb
      create app/assets/images/payments
      create app/assets/images/payments/.keep
      create app/models/concerns
      create app/models/concerns/.keep
      create app/controllers/concerns
      create app/controllers/concerns/.keep
      create config/routes.rb
      create lib/payments.rb
      create lib/tasks/payments_tasks.rake
      create lib/payments/version.rb
      create lib/payments/engine.rb
      create app/assets/config/payments_manifest.js
      create app/assets/stylesheets/payments/application.css
      create bin/rails
      create test/test_helper.rb
      create test/payments_test.rb
      create test/fixtures/files
      create test/fixtures/files/.keep
      create test/controllers
      create test/controllers/.keep
      create test/mailers
      create test/mailers/.keep
      create test/models
      create test/models/.keep
      create test/integration
      create test/integration/.keep
      create test/helpers
      create test/helpers/.keep
      create test/integration/navigation_test.rb
  vendor_app test/dummy
      append /ombulabs.com/Gemfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have created your engine, you can add models, controllers, views, and assets just like you would in a regular Rails application. You can also define your own routes and configurations within the engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use Rails Engines
&lt;/h2&gt;

&lt;p&gt;Using a Rails Engine is also straightforward. The engine needs to be specified inside the &lt;code&gt;Gemfile&lt;/code&gt; and run &lt;code&gt;bundle install&lt;/code&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="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'payments'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s1"&gt;'payments'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make our &lt;code&gt;Payments&lt;/code&gt; engine’s functionality accessible from within our application, we need to mount it in the host application’s &lt;code&gt;config/routes.rb&lt;/code&gt; file. However, it is not always the case as we can use the engine functionality without mounting it:&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;mount&lt;/span&gt; &lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s2"&gt;"/payments"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will mount our &lt;code&gt;Payments&lt;/code&gt; engine at the specified path within your application. You can now use the models, controllers, views, and assets from the engine just like you would in a regular Rails application.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Rails Engines
&lt;/h2&gt;

&lt;p&gt;Rails Engines are particularly useful when you want to modularize your codebase and keep it separate from the core application. This is especially helpful when you are working on a large project with multiple developers, as it allows you to separate responsibilities and avoid conflicts.&lt;/p&gt;

&lt;p&gt;Engines can also be used to create reusable components that can be shared across multiple applications. For example, in an e-commerce context, you could use Rails Engines to build separate modules for different aspects of the site, such as product catalog, shopping cart, payment gateway, and order management.&lt;/p&gt;

&lt;p&gt;Each module could be developed and tested independently and then mounted within the main Rails application. This approach would allow you to scale each module independently as needed, and also make it easier to reuse the code across different e-commerce sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rails Engines are Important
&lt;/h2&gt;

&lt;p&gt;Rails Engines are important because they provide a modular way to organize and share code within a larger Rails application. Here are a few key benefits of using Rails engines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Code Reuse: Rails engines allow you to extract reusable code into separate modules, making it easier to share code across multiple projects. This can save time and effort in development, as you can develop and test functionality once and then reuse it in different contexts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modularity: By breaking up your Rails application into smaller, self-contained modules, you can make your codebase more manageable and easier to maintain. Each engine can be developed and tested independently, allowing you to focus on specific areas of functionality without worrying about breaking changes in the rest of the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encapsulation: Engines provide a way to encapsulate functionality within a well-defined interface. This makes it easier to reason about the code and reduces the risk of introducing bugs or breaking changes in other parts of the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability: Engines can be used to scale your application horizontally by allowing you to add or remove functionality as needed. This can help you to adapt your application to changing business requirements and user needs without having to make major changes to the overall architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customization: Rails engines can be customized to meet the specific needs of different projects or clients. This can be particularly useful in agency or consultancy contexts, where you may need to develop similar functionality across multiple projects but with slight variations in requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By keeping your code organized and modularized, you can improve the overall quality and maintainability of your application.&lt;/p&gt;

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

&lt;p&gt;In conclusion, Rails engines provide a powerful way to organize and share code within a larger Rails application. By breaking up your application into smaller, self-contained modules, you can make your codebase more manageable and easier to maintain. Engines allow you to extract reusable code, encapsulate functionality, and scale your application horizontally by adding or removing functionality as needed. Additionally, engines can be customized to meet the specific needs of different projects or clients.&lt;/p&gt;

&lt;p&gt;While Rails engines may not be appropriate for every project or context, they can be a valuable tool for developers looking to create more modular, maintainable, and scalable applications. Whether you’re building an HR management system, an e-commerce site, or a content management system, Rails engines can help you to develop and reuse functionality in a more efficient and effective way.&lt;/p&gt;

&lt;p&gt;For further reading you can go through the &lt;a href="https://guides.rubyonrails.org/engines.html"&gt;Rails guide for Engines&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Need help modularising your Rails application? &lt;a href="https://www.fastruby.io/#contactus"&gt;Contact us&lt;/a&gt; and have the &lt;a href="https://www.fastruby.io/"&gt;FastRuby.io experts&lt;/a&gt; help you with it!&lt;/p&gt;

</description>
      <category>rails</category>
    </item>
    <item>
      <title>Fixed-cost, Monthly Maintenance Services</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Tue, 23 May 2023 10:23:45 +0000</pubDate>
      <link>https://dev.to/fastruby/fixed-cost-monthly-maintenance-services-371b</link>
      <guid>https://dev.to/fastruby/fixed-cost-monthly-maintenance-services-371b</guid>
      <description>&lt;p&gt;Ever since we started offering &lt;a href="https://fastruby.io"&gt;productized Ruby and Rails upgrade services&lt;/a&gt; and &lt;a href="https://fastruby.io/roadmap"&gt;upgrade roadmaps&lt;/a&gt;, we’ve been interested in helping as many people and companies as possible.&lt;/p&gt;

&lt;p&gt;Unfortunately, in the past we’ve had to turn down companies who wanted to work with us but couldn’t secure the minimum monthly budget to work with our experts.&lt;/p&gt;

&lt;p&gt;I’m pleased to announce that we’re now offering new opportunities for startups and small businesses to work alongside our team.&lt;/p&gt;

&lt;p&gt;In this article, I will share a few new options to collaborate with our team of experts who specialize in &lt;a href="https://fastruby.io/blog/tags/tech-tebt"&gt;technical debt&lt;/a&gt; remediation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;Recently I had the opportunity to connect with a lot of SaaS founders at &lt;a href="https://microconf.com/"&gt;MicroConf&lt;/a&gt; ‘23 which made me realize that there are many entrepreneurs, startups, and small businesses out there that want to pay off technical debt by investing a small amount of money per month.&lt;/p&gt;

&lt;p&gt;While teams understand the need to remediate their technical debt, this very often loses priority to shipping features, releasing patches, and addressing other tasks prioritized in their product roadmaps.&lt;/p&gt;

&lt;p&gt;Although everybody would like to upgrade their app as fast as possible, sometimes that’s just not in the budget. Instead, a good alternative can be to gradually work through your technical debt with a slower-paced retainer model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's included in our monthly maintenance services
&lt;/h2&gt;

&lt;p&gt;Our fixed-cost, monthly retainer will include services to gradually reduce the technical debt in your application. Our services will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby Upgrades&lt;/li&gt;
&lt;li&gt;Rails Upgrades&lt;/li&gt;
&lt;li&gt;Dependency Management&lt;/li&gt;
&lt;li&gt;Performance Monitoring&lt;/li&gt;
&lt;li&gt;Tech Debt Management&lt;/li&gt;
&lt;li&gt;Security Patches&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ruby Upgrades
&lt;/h3&gt;

&lt;p&gt;If your application could use a Ruby upgrade, we will submit a pull request that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--30l3GRKB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/ruby-upgrade-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--30l3GRKB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/ruby-upgrade-example.png" alt="Pull request to upgrade Ruby to 3.2" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Source: &lt;a href="https://github.com/fastruby/points/pull/290/files"&gt;Upgrade to Ruby 3.2 on Points&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If your application is not properly configured to &lt;a href="https://www.fastruby.io/blog/upgrade-rails/dual-boot/dual-boot-with-rails-6-0-beta.html"&gt;dual boot&lt;/a&gt; with &lt;a href="https://github.com/fastruby/next_rails"&gt;&lt;code&gt;next_rails&lt;/code&gt;&lt;/a&gt;, we will submit a PR that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vEn1_pgl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/rails-upgrade-dual-boot-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vEn1_pgl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/rails-upgrade-dual-boot-example.png" alt="Pull request to set up dual booting in a Gemfile" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Source: &lt;a href="https://github.com/fastruby/benchmark.fyi/pull/8/files"&gt;Set up dual booting on Benchmark.fyi&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This will be the basis of our work around dependency management.&lt;/p&gt;

&lt;p&gt;We will make sure that your application can run with both versions of Ruby. If you are on Ruby 2.7, we will make sure that your test suite works with both &lt;a href="https://www.fastruby.io/blog/ruby/upgrades/upgrade-ruby-from-2.7-to-3.0.html"&gt;Ruby 2.7 and 3.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once we fix all the errors in your test suite, we will make sure that your staging environment works with the next version of Ruby. If anything goes wrong, we will make sure we patch all issues before we deploy the change to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rails Upgrades
&lt;/h3&gt;

&lt;p&gt;Similarly, we will gradually tackle Rails upgrade projects. We will use our years of experience to submit many, tiny pull requests that will upgrade your application taking baby steps.&lt;/p&gt;

&lt;p&gt;We will make sure that your application can run with both versions of Rails. If you are on Rails 5.2, we will make sure that your test suite works with both &lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-5-2-to-6-0.html"&gt;Rails 5.2 and 6.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once we fix all the errors in your test suite, we will make sure that your staging environment works with the next version of Rails. If anything goes wrong, we will make sure we patch all issues before we deploy the change to production.&lt;/p&gt;

&lt;p&gt;If you are curious about the dual booting technique, we have been running the Rails upgrade workshop at &lt;a href="https://railsconf.org/"&gt;RailsConf&lt;/a&gt; since 2019. Here is a recording of the workshop we delivered at &lt;a href="https://www.youtube.com/watch?v=Sid39aN_SKk"&gt;RailsConf 2021&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Management
&lt;/h3&gt;

&lt;p&gt;While there are great tools out there that can quickly help you upgrade minor versions of your dependencies (e.g. &lt;a href="https://depfu.com/"&gt;Depfu&lt;/a&gt;), there seems to be a missing link between what we do (&lt;a href="https://www.fastruby.io/"&gt;Ruby/Rails Upgrades&lt;/a&gt;) and what they do (shipping automated pull requests, upgrading one minor version at a time).&lt;/p&gt;

&lt;p&gt;That’s where we come in. We will work on minor and major version upgrades (&lt;a href="https://semver.org/"&gt;according to semver&lt;/a&gt;) for all of your dependencies.&lt;/p&gt;

&lt;p&gt;We will submit one PR at a time. This will give us the opportunity to properly test, deploy, and monitor any issues in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Monitoring
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wRKfW0On--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/new-relic-sample.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wRKfW0On--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/new-relic-sample.png" alt="Sample of a screenshot of NewRelic" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your application is not currently using an Application Performance Monitoring (APM) service (e.g. &lt;a href="https://newrelic.com/"&gt;New Relic&lt;/a&gt;), we will set one up for you. We’ll consider your needs and budget, to make the best recommendation.&lt;/p&gt;

&lt;p&gt;Once your APM is up and running, we will keep track of low performance and high memory load issues. We will share a monthly report with the top issues we noticed as &lt;a href="https://www.fastruby.io/blog/tags/performance"&gt;Ruby and Rails performance experts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want a more in-depth analysis of your application’s performance, we can deliver our highly-rate and always insightful &lt;a href="https://www.fastruby.io/tune"&gt;Tune Report&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While the Tune Report is not included in any of the monthly plans, our clients have found that they can recover their investment in about 3 months.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ece6iz4u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/tune-report-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ece6iz4u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/tune-report-screenshot.png" alt="Screenshot of a sample Tune Report, Rails performance optimization audit provided by FastRuby.io" width="600" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Debt Management
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SdPrA77---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/ruby-critic-monthly-report.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SdPrA77---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/ruby-critic-monthly-report.png" alt="Screenshot of a sample rubycritic report of the Points open source Rails application" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As open source maintainers of technical debt projects like  &lt;a href="https://github.com/whitesmith/rubycritic"&gt;RubyCritic&lt;/a&gt; and  &lt;a href="https://github.com/fastruby/skunk"&gt;Skunk&lt;/a&gt; we know how important it is to keep track of your code complexity, churn, and code coverage metrics.&lt;/p&gt;

&lt;p&gt;On top of that, we know how difficult it is to communicate the problems with consistently increasing technical debt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced development velocity&lt;/li&gt;
&lt;li&gt;Constant regressions&lt;/li&gt;
&lt;li&gt;Undesired side effects when deploying small changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can help with that! Every month you will get a report on your technical debt, not just on the codebase, but also in your development workflow, infrastructure, and best practices.&lt;/p&gt;

&lt;p&gt;In this report we will include any changes that were made to simplify complex code structures, enhance your development workflow, or anything else that was shipped to make your codebase easier to maintain.&lt;/p&gt;

&lt;p&gt;Our goal is to gradually improve &lt;a href="https://fastruby.io/blog/tags/code-quality"&gt;code quality&lt;/a&gt; without disrupting your development team’s operations.&lt;/p&gt;

&lt;p&gt;If you don’t have a shared understanding of what “code quality” really is, we can help you define one that works for your team. After that we can help you “codify” your code quality definition with tools like &lt;code&gt;reek&lt;/code&gt;, &lt;code&gt;rubocop&lt;/code&gt;, and&lt;code&gt;rubycritic&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Patches
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bKe7A6cg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/audit-fastruby-io-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bKe7A6cg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://fastruby.io/blog/assets/images/audit-fastruby-io-screenshot.png" alt="bundle-audit results in the open source application hosted by FastRuby.io" width="680" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture this: On day one of our engagement our team will perform a quick security assessment of your codebase. This will give us an idea of the work to be done to secure your application from known exploits and potential attack vectors.&lt;/p&gt;

&lt;p&gt;Every month we will make security patches that will &lt;a href="https://www.fastruby.io/blog/rails/security/ruby-security-toolkit.html"&gt;level up the security standards for your Rails application&lt;/a&gt;. Depending on the severity of the issues we find, we might prioritize this topic on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Are you ready to make your application more maintainable?&lt;/p&gt;

&lt;p&gt;Considering our 10+ years of experience upgrading applications, and more than &lt;a href="https://twitter.com/etagwerker/status/1658189454715019264?s=20"&gt;20,000 developer hours paying off technical debt&lt;/a&gt;, we believe we can offer meaningful updates to your codebase starting at $1,000 per month:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shito&lt;/strong&gt; : $1,000 per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shohin&lt;/strong&gt; : $2,000 per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Komono&lt;/strong&gt; : $3,000 per month&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each package includes a maximum number of hours per month that we can invest in your application. When naming these packages, we decided to go with Bonsai types because we see a lot of similarities between pruning Bonsai trees and gradually paying off technical debt. 🌳&lt;/p&gt;

&lt;h3&gt;
  
  
  Shito
&lt;/h3&gt;

&lt;p&gt;This is a great package for organizations and companies that either don’t have a lot of technical debt or want to go slow.&lt;/p&gt;

&lt;p&gt;Their test suite might be well-written, their Rails application might be a small monolith, or their development team would be overwhelmed with more than 2 pull requests per month.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shohin
&lt;/h3&gt;

&lt;p&gt;This is a great package for organizations and companies that have some technical debt, know they need to fix it, and are ready to review from 2 to 4 pull requests per month.&lt;/p&gt;

&lt;p&gt;Their test suite might need some attention, their Rails application might have between 50 and 150 models, or they’re one or two versions behind the latest stable release of Ruby and Rails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Komono
&lt;/h3&gt;

&lt;p&gt;This is a great package for organizations and companies that are ready to ship 3x more than if they had chosen the Shito package.&lt;/p&gt;

&lt;p&gt;Usually their Rails application is rather large, their main dependencies (Ruby and Rails) are a few versions behind, their test suite is flaky, or they need to move fast and upgrade things.&lt;/p&gt;

&lt;p&gt;Depending on the plan that you pick, we will invest from 5 to 20 hours per month remediating technical debt in your application/s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategic Projects
&lt;/h2&gt;

&lt;p&gt;We know that every now and then our clients will have one-off, strategic projects they will want to ship as soon as possible and we want to be able to help.&lt;/p&gt;

&lt;p&gt;When that happens, we can offer our services on an hourly basis to ship value in the form of features, infrastructure upgrades, bug fixes, or anything that will make &lt;a href="https://www.fastruby.io/blog/tags/case-study"&gt;a difference in our clients’ businesses&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rescue Services
&lt;/h2&gt;

&lt;p&gt;Our monthly packages don’t include rescue services. If your application needs to be rescued, we can certainly help! We’ve done this many times in the past and we are happy to get you out of a thorny situation.&lt;/p&gt;

&lt;p&gt;For these projects, we need to start with a short, one-week retainer to kickstart the rescue project. This will give us time to assess the situation, come up with a rescue plan, and start executing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;We are used to working with teams of all sizes. From engineering teams of one to teams of 50+ software engineers, we see every engagement as a successful collaboration between our team and your team.&lt;/p&gt;

&lt;p&gt;We thrive when we collaborate with our clients’ engineering team on a daily basis, so we will have a channel to communicate asynchronously. If you need to get on a call, we can do that too!&lt;/p&gt;

&lt;p&gt;Any of the changes that we submit will be open for review and discussion. We will clearly explain why they are necessary, what the changes will do, and what impact they will have in your &lt;a href="https://www.fastruby.io/blog/code-quality/calculate-tech-debt-using-skunk-on-github-actions.html"&gt;tech debt&lt;/a&gt; scorecard.&lt;/p&gt;

&lt;p&gt;Communication is key to us! We provide you with a monthly report on your technical debt, including codebase, development workflow, infrastructure, and best practices. We are always open to hearing your thoughts and needs and answering your questions.&lt;/p&gt;

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

&lt;p&gt;Our commitment to helping people and businesses overcome their technical debt is stronger than ever.&lt;/p&gt;

&lt;p&gt;We are excited to launch our new monthly maintenance packages tailored for non-profit organizations, startups and small businesses. We are certain we will gradually reduce technical debt in their applications.&lt;/p&gt;

&lt;p&gt;Our technical debt remediation services, provided by a team of experts, include dependency management, Ruby upgrades, Rails upgrades,  performance monitoring, tech debt management, and security patches.&lt;/p&gt;

&lt;p&gt;These three affordable plans starting at $1,000 per month are cashflow-friendly, consistently add value to your codebase, and give you access to our team of &lt;a href="https://www.fastruby.io/blog/upgrade-rails/legacy-rails-silently-judging-you.html"&gt;legacy code&lt;/a&gt; experts.&lt;/p&gt;

&lt;p&gt;You can expect to see gradual improvements in your &lt;a href="https://www.fastruby.io/blog/tags/code-quality"&gt;code quality&lt;/a&gt; and overall decreasing technical debt while keeping your development team’s velocity uninterrupted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The typical development organization can increase their feature delivery efficiency by at least 25% by managing technical debt. That’s the equivalent of having &lt;strong&gt;25% more developers without additional staffing costs or&lt;/strong&gt;** coordination needs**.”&lt;/p&gt;

&lt;p&gt;(Source: &lt;a href="https://codescene.com/hubfs/calculate-business-costs-of-technical-debt.pdf"&gt;CodeScene Whitepaper&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What would you do if you had 25% more development efficiency? How much more could your development team deliver in a month?&lt;/p&gt;

&lt;p&gt;Let us be your trusted partner in making your application more maintainable, secure, and efficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fastruby.io/#contactus"&gt;Ready to pay off technical debt? Send us a message!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>maintenance</category>
    </item>
    <item>
      <title>7 Common Mistakes in Rails Upgrades</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Tue, 25 Apr 2023 00:30:00 +0000</pubDate>
      <link>https://dev.to/etagwerker/7-common-mistakes-in-rails-upgrades-3m3a</link>
      <guid>https://dev.to/etagwerker/7-common-mistakes-in-rails-upgrades-3m3a</guid>
      <description>&lt;p&gt;(This article was written by &lt;a href="http://twitter.com/jainrishi15/status/1650507041012604941"&gt;Rishi Jain&lt;/a&gt; and originally published in the &lt;a href="https://www.fastruby.io/blog"&gt;FastRuby.io Blog&lt;/a&gt;) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt; is a popular web application framework that is constantly evolving with new versions being released frequently. While upgrading to a newer Rails version can bring new features, better performance, and security patches/improvements, it can also be a challenging task.&lt;/p&gt;

&lt;p&gt;In this blog post, we will discuss 7 common mistakes made while doing &lt;a href="https://www.fastruby.io/blog/rails/upgrade/rails-upgrade-series.html"&gt;Rails upgrades&lt;/a&gt;and how to avoid them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skipping Versions
&lt;/h2&gt;

&lt;p&gt;We have seen customers trying to upgrade Rails from 5.2 to 7.0 and Ruby from 2.5 to 3.1 all under one single pull request and failing to deploy a successful version on production.&lt;/p&gt;

&lt;p&gt;The problem with this approach is that it becomes extremely difficult to point out where the problem lies when your user encounters a bug in the app.&lt;/p&gt;

&lt;p&gt;Did it happen when you upgraded from &lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-5-2-to-6-0.html"&gt;Rails 5.2 to 6.0&lt;/a&gt; or in any other jump? Did it happen due to a deprecation warning that was supposed to be handled in &lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-6-0-to-6-1.html"&gt;Rails 6.0 to 6.1&lt;/a&gt; jump but you skipped that as you tried to upgrade directly from Rails 5.2 to 7.0?&lt;/p&gt;

&lt;p&gt;Another problem here is that you miss the chance to achieve small wins by deploying relatively small upgrades to production and thus exposing yourself to greater chances of encountering bugs and downtime to your app.&lt;/p&gt;

&lt;p&gt;The only way to avoid these problems is to take a step-wise approach of upgrading only one major or one minor version at a time. If we were to upgrade an app from Rails 5.2 to 7.0, we would first upgrade it to Rails 6.0, deploy to production, then upgrade to 6.1, deploy to production, and then upgrade to 7.0 and deploy to production.&lt;/p&gt;

&lt;p&gt;The Rails Guides also have documentation for changes involving each version jump which makes your job easier. For example: &lt;a href="https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-6-1-to-rails-7-0"&gt;here&lt;/a&gt; is a documentation guide for &lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-6-1-to-7-0.html"&gt;upgrading the app from Rails 6.1 to 7.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you also have to &lt;a href="https://www.fastruby.io/blog/ruby/upgrades/upgrade-ruby-from-2.7-to-3.0.html"&gt;upgrade Ruby&lt;/a&gt; along with Rails, then the ideal approach is to upgrade them individually. This way you can minimize the risk of bugs creeping in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ignoring Deprecation Warnings
&lt;/h2&gt;

&lt;p&gt;We have seen some clients silencing the deprecation warnings instead of addressing them. The reason deprecation warning exists is to alert developers of a behavior of the framework, ruby, or another gem that will not be supported in the future and to give them time to move away from the deprecated behavior which will eventually not be supported.&lt;/p&gt;

&lt;p&gt;The problem with silencing the warning is when the deprecated behavior is no longer supported, it will break the application and the developer will have to either roll back the upgrade or make changes to the app really quickly and no developer would like to be in that situation.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;a href="https://www.fastruby.io/blog/rails/upgrades/deprecation-warnings-rails-guide.html"&gt;addressing the deprecation warnings&lt;/a&gt; are fairly straightforward most of the time, and the deprecation warning message also indicates how to fix / change the code to get rid of the warning.&lt;/p&gt;

&lt;p&gt;It is way easier to &lt;a href="https://www.fastruby.io/blog/rails/upgrades/active-record-5-1-api-changes.html"&gt;address a deprecation warning that is explicit&lt;/a&gt; (it tells you the code, the change and the line that’s triggering it) than fixing a bug that you don’t know where it’s happening and what is causing it.&lt;/p&gt;

&lt;p&gt;We’ve seen hours of work of debugging to end up finding that the bug was due to something that had a deprecation warning which was never addressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading Gems
&lt;/h2&gt;

&lt;p&gt;When you are upgrading Rails, chances are that you are going to upgrade other gems along with it. But, how do you find out which gems need to be upgraded and to what versions? There are 2 ways to go about this.&lt;/p&gt;

&lt;p&gt;First, running &lt;code&gt;bundle update&lt;/code&gt; and then it will update every gem to the most compatible version. The problem with this approach is that since it is going to_update all the possible gems_ with a compatible higher version, you are exposing yourself to more bugs which can come due to code / behavior changes in the upgraded gems.&lt;/p&gt;

&lt;p&gt;Second, running &lt;code&gt;bundle update rails&lt;/code&gt; and then it will break with incompatibility messages across your gem set and with errors indicating which gems need to be updated. The downside to this approach is that it takes longer as you have to manually upgrade gems iteratively until the &lt;code&gt;bundle update&lt;/code&gt; is successful.&lt;/p&gt;

&lt;p&gt;The upsides are huge though as chances of bugs creeping comes down as you have only upgraded gems that absolutely needed to be upgraded.&lt;/p&gt;

&lt;p&gt;You can read more about it &lt;a href="https://www.fastruby.io/blog/ruby/dual-boot/generating-gemfile-next-lock.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undocumented Monkey Patches and Forking gems
&lt;/h2&gt;

&lt;p&gt;Yes, Ruby is great because the powers it gives you and one of them is monkey patching existing behavior. This is great because it solves your problems in the short term.&lt;/p&gt;

&lt;p&gt;But we have seen enough projects where the monkey patched behavior is left with no comments explaining why it was done in the first place and the developer who did this is no more working at the organization to explain and now you are left with no option but to make sense of the patch work all by yourself which is very close to guess work.&lt;/p&gt;

&lt;p&gt;Another big problem we have encountered over the years is forking gems. Lots of times, developers fork open source gems and make changes to it to fit their needs.&lt;/p&gt;

&lt;p&gt;But those changes are never submitted to the open source project and the reason for the fork is left to yourself without documenting it. Now it is the team who is working on the upgrade that is left to make sense of why the fork was done, and is it safe to go the released rubygems version of it or make the fork work with the upgraded Rails and other gems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lack of test coverage or testing strategy
&lt;/h2&gt;

&lt;p&gt;To ensure that the upgrade of the Rails app is successfully released on production, you need either of the 2 things at least.&lt;/p&gt;

&lt;p&gt;First, a good test coverage of your application. Anything above 80% test coverage is considered good if it includes coverage of the critical paths of the applications.&lt;/p&gt;

&lt;p&gt;Second, awareness of all the critical paths of the application and ability to test them manually.&lt;/p&gt;

&lt;p&gt;If you do not have either of the 2 things in place, it increases the chances of encountering bugs upon releasing it on production. Even with both the strategies in place, you can still set yourself for a buggy release on production and that can be due to not having a dedicated QA team or QA role defined in your workflow.&lt;/p&gt;

&lt;p&gt;When the developer doing the code review on the pull request ends up doing the QA of it as well it is not an ideal situation. It can lead to bugs not caught before they are released to your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not using the right tools
&lt;/h2&gt;

&lt;p&gt;There are many ways to go about upgrading your application, but choosing the right tools and the right strategy can go a long way in making your experience smooth.&lt;/p&gt;

&lt;p&gt;Something as trivial as branching and code arrangement strategy holds a lot of importance in your workflow. We have seen a lot of teams struggle or end up doing repetitive work because of lack of clearly defined strategy.&lt;/p&gt;

&lt;p&gt;To avoid confusion on how to run the upgrades, we contribute and maintain the &lt;a href="https://github.com/fastruby/next_rails"&gt;next_rails&lt;/a&gt; gem which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helps us in running 2 different versions of Ruby or Rails in the same branch&lt;/li&gt;
&lt;li&gt;Facilitates running specs for the 2 different versions of Ruby or Rails from the same branch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This goes a long way in debugging issues while doing upgrades without switching branches. It also helps in implementing a gradual deployment strategy with Kubernetes.&lt;/p&gt;

&lt;p&gt;We have also seen customers trying to do everything “the Rails way” when it does not make sense for them.&lt;/p&gt;

&lt;p&gt;For example, Active Storage is a great gem and very useful for someone allowing users to upload files. But one of our customers wanted to use Active Storage even though their use case did not fit to use it.&lt;/p&gt;

&lt;p&gt;What they already had made more sense for them. Using Active Storage would have made their systems more complex. So it is also important to know when to move away from the defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Having a Rollback Plan
&lt;/h2&gt;

&lt;p&gt;Finally, not having a rollback plan is a common mistake made while upgrading Ruby or Rails.&lt;/p&gt;

&lt;p&gt;Despite careful planning, unexpected issues can arise during the deployment. It is important to have a rollback plan in case of any issues that may arise during the deployment process.&lt;/p&gt;

&lt;p&gt;A rollback plan should include steps to revert to the previous version of Rails, restore db backups, and fix issues that caused the rollback.&lt;/p&gt;

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

&lt;p&gt;Upgrading your Ruby or Rails version is essential for keeping your application secure and up to date.&lt;/p&gt;

&lt;p&gt;However, upgrading can be a challenging task, especially when you make common mistakes.&lt;/p&gt;

&lt;p&gt;In this article, we discussed 7 common mistakes that developers make when upgrading Ruby or Rails and how to avoid them. By avoiding these mistakes, you can make the upgrade process smoother and less stressful.&lt;/p&gt;

&lt;p&gt;In conclusion, upgrading Rails can be a daunting task, but with the right approach, you can make it a seamless process.&lt;/p&gt;

&lt;p&gt;Happy upgrading!&lt;/p&gt;

&lt;p&gt;PS: Need help upgrading Ruby or Rails to their latest stable version? &lt;a href="https://www.fastruby.io"&gt;We have some availability to help your team upgrade Ruby/Rails&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>upgrades</category>
    </item>
    <item>
      <title>How to Upgrade Rails Without a Test Suite</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Wed, 13 Jan 2021 09:00:00 +0000</pubDate>
      <link>https://dev.to/fastruby/how-to-upgrade-rails-without-a-test-suite-403h</link>
      <guid>https://dev.to/fastruby/how-to-upgrade-rails-without-a-test-suite-403h</guid>
      <description>&lt;p&gt;Sometimes you will be caught between a rock and a hard place. For example: You really need to upgrade your Rails application because Heroku is discontinuing your stack in two weeks so you don't have the time to write an entire test suite.&lt;/p&gt;

&lt;p&gt;Sometimes the situation will be that your boss really needs you to upgrade Ruby or Rails to use a version that gets security updates and they won't allow you to write tests beforehand.&lt;/p&gt;

&lt;p&gt;This article will explain how to ship a Rails upgrade project without a test suite. If your application has no tests, you will learn how to upgrade without having to write tests first.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up Staging&lt;/li&gt;
&lt;li&gt;Check the Changelog&lt;/li&gt;
&lt;li&gt;Write a Testing Script&lt;/li&gt;
&lt;li&gt;Set up Error Tracking&lt;/li&gt;
&lt;li&gt;Set up Dual Booting&lt;/li&gt;
&lt;li&gt;Upgrade Development and Test&lt;/li&gt;
&lt;li&gt;Deploy to Staging and Test&lt;/li&gt;
&lt;li&gt;Deploy to Production&lt;/li&gt;
&lt;li&gt;If you have the time, write integration tests&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Set up Staging
&lt;/h2&gt;

&lt;p&gt;Have a staging server that is identical to your production server. You will need to thoroughly test your changes in a staging environment before you deploy any changes to production.&lt;/p&gt;

&lt;p&gt;Strive to make this environment as similar to production as possible. Fill it up with production-like data, so that you can test real world scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Changelog
&lt;/h2&gt;

&lt;p&gt;Many of the changes in the new Rails version won't affect your application. Read the most notable changes in the changelog and manually find whether the APIs that changed are getting used in your application's code.&lt;/p&gt;

&lt;p&gt;In this step there will be a lot of &lt;em&gt;grepping&lt;/em&gt; or finding in files within your code editor. If you want to learn how to do this, we wrote an article about that: &lt;a href="https://www.fastruby.io/blog/rails/upgrades/our-rails-upgrade-process.html"&gt;How we upgrade Rails applications&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Write a Testing Script
&lt;/h2&gt;

&lt;p&gt;If you know the application from top to bottom, write down several manual test scenarios. If you don't, work with the product owner to define a set of steps that you can run to smoke test the application in your development, staging, and production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Set up Error Tracking
&lt;/h2&gt;

&lt;p&gt;If you don't have this configured, make sure that you set it up before you deploy anything to staging or production.&lt;/p&gt;

&lt;p&gt;There are many options when it comes to error tracking. Some of the most popular alternatives are &lt;a href="https://sentry.io/"&gt;Sentry&lt;/a&gt;; &lt;a href="https://www.honeybadger.io"&gt;Honeybadger&lt;/a&gt;; or &lt;a href="https://rollbar.com"&gt;Rollbar&lt;/a&gt;. This will come in handy when you deploy your code and you get real users using your application on the new version of Rails.&lt;/p&gt;

&lt;p&gt;Considering your application does not have a test suite, I can guarantee that you will get exception notifications once your code is live. You want to make sure that you can get all the necessary information so that you can quickly patch those bugs.&lt;/p&gt;

&lt;p&gt;Even applications with a solid test suite and great code coverage will find exceptions in production. So this is a great idea even if you are not deploying a major Rails upgrade. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Set up Dual Booting
&lt;/h2&gt;

&lt;p&gt;This will help you with the next steps across all your environments. Using this technique you will save a lot of time, because you will be able to run your application with Rails X or Y by changing a single environment variable.&lt;/p&gt;

&lt;p&gt;We have explained how to dual boot in this article:&lt;a href="https://www.fastruby.io/blog/upgrade-rails/dual-boot/dual-boot-with-rails-6-0-beta.html"&gt;How to Dual Boot Ruby on Rails&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Upgrade Development and Test
&lt;/h2&gt;

&lt;p&gt;If you have set up dual booting correctly, you will be able to run your current Rails version like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec rails server

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

&lt;/div&gt;



&lt;p&gt;And your new Rails version like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next bundle exec rails server

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

&lt;/div&gt;



&lt;p&gt;Now you can start smoke testing your application in your development environment. This step will include a lot of steps that look like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read and execute your testing script
&lt;/li&gt;
&lt;li&gt;Monitor your logs and error tracking service
&lt;/li&gt;
&lt;li&gt;Find issues&lt;/li&gt;
&lt;li&gt;Patch them&lt;/li&gt;
&lt;li&gt;And repeat...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you feel comfortable that you have tested your critical user paths and everything looks good, you can move on to deploying your changes to your staging environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Deploy to Staging and Test
&lt;/h2&gt;

&lt;p&gt;Now you are at a point where you can involve your QA team. Once you have deployed and tested your changes in staging, you can involve more people in helping you manually test critical user flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Deploy to Production and Test
&lt;/h2&gt;

&lt;p&gt;There are two safe-ish ways to deploy your Rails upgrade to production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gradual deployment&lt;/li&gt;
&lt;li&gt;Full deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Gradual deployment
&lt;/h3&gt;

&lt;p&gt;This is another step that benefits from your dual booting code. You can deploy your changes to only a few application instances in your cluster. Then you will have your cluster running both versions in parallel (Rails X and Y).&lt;/p&gt;

&lt;p&gt;You can set up your production environment to direct only 10% of the traffic to the new version of your code. This article explains how you can do that:&lt;a href="https://engineering.adwerx.com/continuously-integrating-a-major-rails-upgrade-53a0d2e12505"&gt;Continuously Integrating a Major Rails Upgrade&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Full deployment
&lt;/h3&gt;

&lt;p&gt;If your application does not get a lot of traffic at night, you might want to deploy your changes to all your visitors then. This approach is certainly riskier because slower traffic means fewer users which means fewer "testers" for real world scenarios.&lt;/p&gt;

&lt;p&gt;In both scenarios, you will eventually sit and wait for errors. Depending on the severity of the errors, you might want to roll back your changes and go back tostep 6.&lt;/p&gt;

&lt;p&gt;If there are only a few minor bugs, you might want to hot fix them in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Integration Tests
&lt;/h2&gt;

&lt;p&gt;If you have the time, I would highly recommend writing some integration tests. You can use RSpec and Capybara to write some simple tests to view them in a browser.&lt;/p&gt;

&lt;p&gt;You don't have to get too creative when writing these tests, you can basically write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# spec/features/homepage_spec.rb
require "rails_helper"

RSpec.describe "Homepage at FastRuby.io", js: true do
  it "does not blow up" do
    visit "/"

    expect(page).to have_text("Need to upgrade Rails but don't have the time?")
  end
end

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

&lt;/div&gt;



&lt;p&gt;You can write basic, smoke-testy integration tests that mimic the behavior of end users and get to a non-zero amount of code coverage in a few minutes. If you have the time, doing this will save you time in your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary (TL;DR)
&lt;/h2&gt;

&lt;p&gt;Someone is going to test your application. It could be you, writing automated tests and increasing code coverage. It might be your QA team, testing things work as expected in staging and production. In the worst case, it will be your end users trying to do something in production.&lt;/p&gt;

&lt;p&gt;If you don't have a test suite, it does not mean that you cannot upgrade a dependency of your application. It usually means that it will take longer than if you had a well-written test suite, because there will be a lot of manual testing during the project.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>How to Prepare Your Rails App for an Upgrade</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Tue, 29 Dec 2020 09:00:00 +0000</pubDate>
      <link>https://dev.to/fastruby/how-to-prepare-your-rails-app-for-an-upgrade-1am0</link>
      <guid>https://dev.to/fastruby/how-to-prepare-your-rails-app-for-an-upgrade-1am0</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is part of our Rails Upgrade series. To see more of them, &lt;a href="https://fastruby.io/blog/tags/upgrades"&gt;click here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This article will cover the most important aspects that you need to know to prepare your &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; application for working on an upgrade.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test Coverage&lt;/li&gt;
&lt;li&gt;Staging and Production&lt;/li&gt;
&lt;li&gt;Patch Version&lt;/li&gt;
&lt;li&gt;Incompatibilities&lt;/li&gt;
&lt;li&gt;Dual Boot&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Code Coverage
&lt;/h3&gt;

&lt;p&gt;Not all applications are good candidates for a Rails upgrade project. We strongly advise against upgrading big applications which are running in production with minimal test coverage.&lt;/p&gt;

&lt;p&gt;Make sure that you have at least 80% test coverage before starting the upgrade project. If you don't have a solid test suite (or a dedicated QA team), you will likely find many problems which will force you to roll back the upgrades as soon as they hit production.&lt;/p&gt;

&lt;p&gt;You can easily calculate your coverage by using &lt;a href="https://github.com/colszowka/simplecov"&gt;simplecov&lt;/a&gt;. Here is a &lt;a href="https://www.fastruby.io/blog/rails/upgrades/simplecov/rails-upgrades-simplecov.html"&gt;tutorial&lt;/a&gt; about how to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Staging and Production
&lt;/h3&gt;

&lt;p&gt;We advise all of our clients to follow a &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/"&gt;Git flow&lt;/a&gt; workflow and to actively manage at least two environments: staging and production.&lt;/p&gt;

&lt;p&gt;Every change should be code reviewed using pull requests and it should run the entire test suite. Once all checks have passed, changes should be deployed to staging. After your QA team has tested your critical flow in staging, you can deploy the changes to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Patch Version
&lt;/h3&gt;

&lt;p&gt;Before working on an upgrade you should make sure that you are running the application with the latest patch version. That way, you make sure that the latest security patches have been installed. On top of that, with more recent versions, you will get a series of deprecation warnings that will be useful in finding out what needs to be done.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Incompatibilities
&lt;/h3&gt;

&lt;p&gt;Have you ever gotten tangled in dependencies? You need to upgrade dependency A, but that's incompatible with Rails 5.0 because dependency B (which is a dependency of A) is not compatible with that version of ActiveRecord).&lt;/p&gt;

&lt;p&gt;Before you start going down the rabbit hole, make sure to check your &lt;code&gt;Gemfile.lock&lt;/code&gt; for incompatibilities. For that, you can use this website: &lt;a href="https://railsbump.org/"&gt;https://railsbump.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That will give you an idea of how many dependencies are not compatible with Rails 4, 5, or 6.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Dual Boot
&lt;/h3&gt;

&lt;p&gt;To help you switch between your current Rails version and the new one, you can create a dual boot mechanism. The fastest way is to install the handy gem &lt;a href="https://github.com/fastruby/next_rails"&gt;next_rails&lt;/a&gt;. You can initialize it by doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gem install next_rails
$ next --init

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

&lt;/div&gt;



&lt;p&gt;You can then set up two Rails versions in your Gemfile like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if next?
  gem 'rails', '~&amp;gt; 6.0.0'
else
  gem 'rails', '~&amp;gt; 5.2.3'
end

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

&lt;/div&gt;



&lt;p&gt;Sometimes dependencies are backwards compatible with the current version of Rails. Within the libraries, you will find code that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if Rails::VERSION &amp;gt;= 5.1
  # does X
else
  # does Y
end

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

&lt;/div&gt;



&lt;p&gt;If that is the case, then you might be able to just upgrade the dependency using &lt;code&gt;bundle update&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now that you have laid the groundwork for you upgrade, it is time to start the work itself. For details on what you specific version upgrade will require, check out the corresponding guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-to-rails-3.html"&gt;How to upgrade from Rails 2.3 to 3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-to-rails-3-1.html"&gt;How to upgrade from Rails 3.0 to 3.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-to-rails-3-2.html"&gt;How to upgrade from Rails 3.1 to 3.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-3-2-to-4-0.html"&gt;How to upgrade from Rails 3.2 to 4.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-4-0-to-4-1.html"&gt;How to upgrade from Rails 4.0 to 4.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-4-1-to-4-2.html"&gt;How to upgrade from Rails 4.1 to 4.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-4-2-to-5-0.html"&gt;How to upgrade from Rails 4.2 to 5.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-5-0-to-5-1.html"&gt;How to upgrade from Rails 5.0 to 5.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-5-1-to-5-2.html"&gt;How to upgrade from Rails 5.1 to 5.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastruby.io/blog/rails/upgrades/upgrade-rails-from-5-2-to-6-0.html"&gt;How to upgrade from Rails 5.2 to 6.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Churn vs. Complexity vs. Code Coverage</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Wed, 13 May 2020 02:25:00 +0000</pubDate>
      <link>https://dev.to/fastruby/churn-vs-complexity-vs-code-coverage-38fm</link>
      <guid>https://dev.to/fastruby/churn-vs-complexity-vs-code-coverage-38fm</guid>
      <description>&lt;p&gt;Churn vs. Complexity analysis is a great way to find insights about the maintainability of a project. Two of my favorite authors have written great articles about the Churn vs. Complexity graph:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.agileconnection.com/article/getting-empirical-about-refactoring"&gt;Getting Empirical about Refactoring&lt;/a&gt; by Michael Feathers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sandimetz.com/blog/2017/9/13/breaking-up-the-behemoth"&gt;Breaking up the Beheamoth&lt;/a&gt; by Sandi Metz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This two-dimensional graph can be very useful in finding the files that are the hardest to maintain in your application. In this article I will explain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How you can calculate these metrics and use them in your legacy project&lt;/li&gt;
&lt;li&gt;How code coverage metrics can guide your technical debt's collection efforts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Churn
&lt;/h2&gt;

&lt;p&gt;Churn by itself is a useful metric. It will tell you which files are the ones that are constantly changing. Change takes time, so files that are constantly changing are costing you time and money.&lt;/p&gt;

&lt;p&gt;It will make you wonder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why are these files changing so much?&lt;/li&gt;
&lt;li&gt;Are requirements constantly changing?&lt;/li&gt;
&lt;li&gt;Are we truly understanding business rules correctly?&lt;/li&gt;
&lt;li&gt;Is our application poorly designed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your legacy application is written in Ruby, you can use a gem called &lt;a href="https://github.com/danmayer/churn"&gt;&lt;code&gt;churn&lt;/code&gt;&lt;/a&gt; to find the files that are constantly changing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculating Churn in Ruby
&lt;/h3&gt;

&lt;p&gt;You can install &lt;a href="https://rubygems.org/gems/churn"&gt;&lt;code&gt;churn&lt;/code&gt;&lt;/a&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install churn

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then call it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;churn -e rb --start_date "10 years ago" lib -i spec

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will show you a list of files sorted by their churn count (number of times that the file has changed in the SCM that you are using)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**********************************************************************
* Project Churn
**********************************************************************

Files
+-----------------------------------------------------------------------------------+---------------+
| file_path | times_changed |
+-----------------------------------------------------------------------------------+---------------+
| lib/metric_fu.rb | 50 |
| lib/metric_fu/version.rb | 44 |
| lib/metric_fu/configuration.rb | 36 |
| lib/metric_fu/reporting/templates/awesome/awesome_template.rb | 29 |
| lib/metric_fu/io.rb | 23 |
| lib/metric_fu/formatter/html.rb | 23 |
| lib/base/configuration.rb | 23 |
| lib/metric_fu/run.rb | 22 |
| lib/metric_fu/metrics/saikuro/saikuro.rb | 20 |
| lib/metric_fu/metric.rb | 20 |
+-----------------------------------------------------------------------------------+---------------+

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By itself, this metric provides a limited insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These are the files that have changed the most since the beginning of the project&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It doesn't provide insights into why these files are changing as much as they do. If you open these files in your editor, you might find that files with high churn are super complex or super simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity
&lt;/h2&gt;

&lt;p&gt;As you go about making your changes, you will introduce complexity. There is noway around it. The best way to have no complexity is to have no code.&lt;/p&gt;

&lt;p&gt;It doesn't matter whether you are a rockstar object-oriented architect or a novice programmer. You will introduce complexity into a project.&lt;/p&gt;

&lt;p&gt;"Complexity" should not be considered a negative term. "Unnecessary complexity" might be considered an anti-pattern. Good object-oriented programming calls for &lt;a href="https://wiki.c2.com/?CouplingAndCohesion"&gt;loose coupling and high cohesion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You want modules that follow &lt;a href="http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod"&gt;SOLID&lt;/a&gt; principles. When you notice your module is becoming extremely complex, you will want to refactor it into two or more modules. These modules will send and receive messages between each other, which will increase coupling (as loosely as possible) and hopefully improve cohesion per module.&lt;/p&gt;

&lt;p&gt;As you go about submitting pull request to ship new features, change existing ones, or patch bugs, the maintainability of your project will vary according to the modules you introduce or change.&lt;/p&gt;

&lt;p&gt;The bigger the project, the more complexity, the harder it will be to maintain it, because there will be more moving pieces and loosely coupled modules.&lt;/p&gt;

&lt;p&gt;If you refactor a huge module, into two smaller modules, you will notice that &lt;a href="https://docs.codeclimate.com/docs/cognitive-complexity"&gt;cognitive complexity&lt;/a&gt; per module will (hopefully) get better. You won't have one huge, complex module anymore, you will have two or more modules that are easier to understand.&lt;/p&gt;

&lt;p&gt;Modules that have one and only one responsibility will be easier to maintain and test. Future changes will be easier because you will be able to quickly understand what the module is doing.&lt;/p&gt;

&lt;p&gt;In the next section I will explain how you can calculate complexity for all your Ruby modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculating Complexity in Ruby
&lt;/h3&gt;

&lt;p&gt;There are many tools out there (e.g. &lt;a href="https://www.fastruby.io/blog/ruby/quality/code-quality-ruby-gems.html"&gt;three awesome libraries to assess code quality&lt;/a&gt;) that can help you find the most complex files in your project. One of the most popular tools in the Ruby world is &lt;a href="https://github.com/seattlerb/flog"&gt;&lt;code&gt;flog&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/julianrubisch/attractor"&gt;Attractor&lt;/a&gt; uses &lt;code&gt;flog&lt;/code&gt; to calculate complexity for each module. I really like the report that it generates. You can see all the modules in one page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4_w1II9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fastruby.io/blog/assets/images/attractor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4_w1II9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fastruby.io/blog/assets/images/attractor.png" alt="Attractor Report for MetricFu Ruby gem"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By itself this metric can take you in the wrong direction. Sometimes you will find extremely complex files which never change. So they are likely not your priority when it's time to refactor code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Churn vs. Complexity
&lt;/h2&gt;

&lt;p&gt;In his article, Michael Feathers, states the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nXaKyBa---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fastruby.io/blog/assets/images/churn-vs-complexity-graph-by-michael-feathers.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nXaKyBa---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://fastruby.io/blog/assets/images/churn-vs-complexity-graph-by-michael-feathers.jpg" alt="Churn vs Complexity by Michael Feathers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These diagrams give us quite a bit of information. The upper right quadrant is particularly important. These files have a high degree of complexity, and they change quite frequently. [...] These classes are particularly ripe for arefactoring investment&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I agree that this graph is great for finding &lt;em&gt;refactoring candidates&lt;/em&gt;. The problem is that sometimes these candidates have no tests to verify their behavior. So sometimes we don't have time to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write tests&lt;/li&gt;
&lt;li&gt;Refactor complex files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes we have to pick one or the other. So in my opinion it would be great to include another metric into our analysis: Code Coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Coverage
&lt;/h2&gt;

&lt;p&gt;When we start maintaining a module, we don't usually just look at its churn and complexity. We also look at the tests that describe its expected behavior.&lt;/p&gt;

&lt;p&gt;Usually a module that has a decent test suite (basic code coverage) will be easier to understand than one without tests. We will have one more resource to learn about a module's behavior.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code coverage metrics don't tell whether the test suite is good or bad. It tells you how many statements of your application are exercised by your test suite. You should not blindly trust code coverage percentages without doing a quick code review of the tests that are present.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't you just love it when a module has great tests that describe the expected behavior of its public API?&lt;/p&gt;

&lt;h2&gt;
  
  
  Churn vs. Complexity vs. Code Coverage
&lt;/h2&gt;

&lt;p&gt;When I look at all the modules in the project, I want to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many times has this file changed since the beginning of the project? (Churn)&lt;/li&gt;
&lt;li&gt;How complex is this module? (Complexity)&lt;/li&gt;
&lt;li&gt;What's the code coverage associated with this module? (Code Coverage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This new dimension will tell us which files are the most changed, the most complicated, and the least covered with tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refactoring modules that lack proper tests can quickly turn into a nightmare. You don't want your refactoring efforts to blow up in your face when changes hit production. And you probably don't want to test all your changes manually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By adding a third dimension to the churn vs complexity graph, you will be able to gather new insights about your modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should I refactor this module?&lt;/li&gt;
&lt;li&gt;Should I increase test coverage before I refactor this module?&lt;/li&gt;
&lt;li&gt;Do I have time to do both this week?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Calculating a Churn vs. Complexity vs. Code Coverage Graph in Ruby
&lt;/h3&gt;

&lt;p&gt;Last year I published a library that can help you take all these metrics into account: &lt;a href="https://github.com/fastruby/skunk"&gt;Skunk&lt;/a&gt;. It relies on &lt;a href="https://github.com/whitesmith/rubycritic"&gt;RubyCritic&lt;/a&gt; and &lt;a href="https://github.com/colszowka/simplecov"&gt;SimpleCov&lt;/a&gt; to get all the metrics it needs.&lt;/p&gt;

&lt;p&gt;You can install it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install skunk

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;skunk lib/

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It won't generate a graph (yet) but it will generate a table with all the modules in the &lt;code&gt;lib&lt;/code&gt; directory. It will sort files from worst to best (in terms of technical debt):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
| file | skunk_score | churn_times_cost | churn | cost | coverage |
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
| lib/skunk/cli/commands/default.rb | 166.44 | 1.6643999999999999 | 3 | 0.5548 | 0 |
| lib/skunk/cli/application.rb | 139.2 | 1.392 | 3 | 0.46399999999999997 | 0 |
| lib/skunk/cli/command_factory.rb | 97.6 | 0.976 | 2 | 0.488 | 0 |
| test/test_helper.rb | 75.2 | 0.752 | 2 | 0.376 | 0 |
| lib/skunk/rubycritic/analysed_module.rb | 48.12 | 1.7184 | 2 | 0.8592 | 72.72727272727273 |
| test/lib/skunk/cli/commands/status_reporter_test.rb | 45.6 | 0.456 | 1 | 0.456 | 0 |
| lib/skunk/cli/commands/base.rb | 29.52 | 0.2952 | 3 | 0.0984 | 0 |
| lib/skunk/cli/commands/status_reporter.rb | 8.0 | 7.9956 | 3 | 2.6652 | 100.0 |
| test/lib/skunk/rubycritic/analysed_module_test.rb | 2.63 | 2.6312 | 2 | 1.3156 | 100.0 |
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/fastruby/skunk#what-is-the-skunkscore"&gt;SkunkScore&lt;/a&gt; is a function of complexity and code coverage.&lt;/p&gt;

&lt;p&gt;Let's say that your application has two extremely complex modules: &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;product&lt;/code&gt;. Let's assume that both of them have changed a lot (churn count at 100) and are extremely complex (1,000 flog points).&lt;/p&gt;

&lt;p&gt;In this example, if &lt;code&gt;user&lt;/code&gt; has more tests than &lt;code&gt;product&lt;/code&gt;, &lt;code&gt;user&lt;/code&gt;'s SkunkScore will be lower than &lt;code&gt;product&lt;/code&gt;'s. Next week you could start refactoring &lt;code&gt;user&lt;/code&gt; or increasing code coverage for &lt;code&gt;product&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By looking at this table you will be able to quickly decide about what to do: You might want to write tests for a complex module, refactor a complex module that is well covered by integration tests, or both!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Coverage as a Prioritization Mechanism
&lt;/h2&gt;

&lt;p&gt;In big projects you might notice hundreds of modules in the upper right quadrant of the Churn vs. Complexity graph. You might ask yourself: What do I do first? Do I write a test for module User? Do I refactor module Product?&lt;/p&gt;

&lt;p&gt;I strongly believe that Code Coverage is a great signal for complementing churn and complexity metrics. I hope you can use it in your next legacy project to gradually pay off technical debt!&lt;/p&gt;

</description>
      <category>churn</category>
      <category>complexity</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Our Guide for Unmaintained Open Source Projects</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Thu, 26 Mar 2020 11:16:00 +0000</pubDate>
      <link>https://dev.to/fastruby/our-guide-for-unmaintained-open-source-projects-4g3g</link>
      <guid>https://dev.to/fastruby/our-guide-for-unmaintained-open-source-projects-4g3g</guid>
      <description>&lt;p&gt;There are some really &lt;a href="https://opensource.guide/starting-a-project/"&gt;great guides for starting a new open source projects&lt;/a&gt;, yet when it comes to dealing with a possibly abandoned, unmaintained project, there is no definitive guide for users, contributors, or maintainers.&lt;/p&gt;

&lt;p&gt;I hope that this can be a useful guide for our community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;When do you declare that an open source project has been abandoned? How manydays have to go by until you start maintaining your own fork? What's thestandard for communicating with maintainers, contributors, and users? How doyou avoid &lt;code&gt;n&lt;/code&gt; competing OSS forks of popular projects? How do you avoid duplicated work by people who want to maintain popular, but unmaintained OSS projects? What's the best way to find &lt;strong&gt;that one fork&lt;/strong&gt; everybody is using?&lt;/p&gt;

&lt;h2&gt;
  
  
  Nights and Weekends
&lt;/h2&gt;

&lt;p&gt;Too many applications out there are using libraries that depend on peoplehaving enough time during nights and weekends to work on their side projects.Most of the maintainers out there are not paid for their work. They might have_some help_ from their employers (e.g. &lt;a href="https://www.ombulabs.com"&gt;Ombu Labs&lt;/a&gt; sponsors open source efforts), &lt;a href="https://tidelift.com"&gt;Tidelift&lt;/a&gt;, &lt;a href="https://github.com/sponsors"&gt;GitHub Sponsorships&lt;/a&gt;, &lt;a href="https://gitcoin.co"&gt;Gitcoin&lt;/a&gt;, or &lt;a href="https://opencollective.com"&gt;OpenCollective&lt;/a&gt;, but most projects don't have financial support.&lt;/p&gt;

&lt;p&gt;No wonder many OSS maintainers burn out after years maintaining their project.What happens when a maintainer burns out, starts using a different tech stack, or even worse, dies?&lt;/p&gt;

&lt;p&gt;As users, we should be entirely grateful for their hard work, but we should also find a way to continue maintaining their OSS project, by starting a new fork or backing an existing one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposal
&lt;/h2&gt;

&lt;p&gt;Depending on your role in the project, here are some strategies that could help users and contributors, or maintainers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For users and contributors: Continuing maintenance for an abandoned OSS project&lt;/li&gt;
&lt;li&gt;For maintainers: Finding someone else to maintain your OSS project&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;There is no clear way to continuing maintenance of an abandoned OSS project. There are definitely great guides that share a few important concepts, but not a lot of action steps for the case when an OSS project ends in &lt;em&gt;maintenance limbo&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opensource.guide/best-practices"&gt;Best Practices for Maintainers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linuxfoundation.org/resources/open-source-guides/winding-down-an-open-source-project/"&gt;Winding Down an Open Source Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/the-node-js-collection/healthy-open-source-967fa8be7951"&gt;Healthy Open Source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advice for Open Source Users and Contributors
&lt;/h2&gt;

&lt;p&gt;What can you do as someone who actively uses or contributes to the OSS project? For example: What can you do when you &lt;strong&gt;really really&lt;/strong&gt; need to have support for &lt;a href="https://edgeguides.rubyonrails.org/6_0_release_notes.html"&gt;Rails 6.0&lt;/a&gt; for your application but this library is blocking you?&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Judgement for Assessing Abandonment
&lt;/h3&gt;

&lt;p&gt;First things first, use your best judgment to determine whether the project is truly abandoned or just feature complete.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are many projects out there that are not being actively maintained because they do one little thing really well. Think about these projects as the outliers because they are feature complete and have no bugs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are some things to consider when judging the state of an OSS project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When was the last time there was a commit to the &lt;code&gt;master&lt;/code&gt; branch?&lt;/li&gt;
&lt;li&gt;When was the last time there was a commit to a non-master branch?&lt;/li&gt;
&lt;li&gt;When was the last time there was a comment in an issue by a maintainer?&lt;/li&gt;
&lt;li&gt;When was the last time there was a code review from one of the maintainers?&lt;/li&gt;
&lt;li&gt;Is the test suite still passing if you submit one small change to the project?&lt;/li&gt;
&lt;li&gt;When was the last version of the library published? (Example: for a Ruby gem,you can check in &lt;a href="https://rubygems.org"&gt;https://rubygems.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;When was the last time an issue or pull request was closed by a maintainer?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inquire
&lt;/h3&gt;

&lt;p&gt;When it is not clear, it is okay to inquire about the status of the project. If someone hasn't done it already, you can submit an issue to the project asking about the state of things.&lt;/p&gt;

&lt;p&gt;Before you submit your inquiry, you might want to submit a pull request with asmall improvement to the project. If the change is small enough and it improves things, then it should be easy to review or close. Make sure that the test suite passes in CI.&lt;/p&gt;

&lt;p&gt;You can start your inquiry by saying that you appreciate their dedication and thank them for their hard work over the years, then you can ask if they're looking for help maintaining the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not&lt;/strong&gt; demand an answer from the maintainers. Maintainers don't owe you anything because software is provided &lt;em&gt;as is&lt;/em&gt;, so you will be lucky if you get a response to a nice request. So, &lt;strong&gt;please be nice&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You don't need to offer yourself as a potential maintainer for the project, maybe there are other people out there who are in a better position to continue maintaining the project.&lt;/p&gt;

&lt;p&gt;If you don't get any response for a month, then you can move on to the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Your Own Fork
&lt;/h3&gt;

&lt;p&gt;You could start your own OSS project by creating a fork. Before you do that, make sure that you check the &lt;a href="https://help.github.com/en/github/visualizing-repository-data-with-graphs/viewing-a-repositorys-network"&gt;contribution network for the project&lt;/a&gt;. There might be someone else updating a fork that already has all the changes youneed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fun fact: &lt;a href="https://www.bacula.org/why-forking-is-bad/"&gt;Forking a project used to be considered a "bad word"&lt;/a&gt; but I think the rise of GitHub turned that around.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is what &lt;a href="https://Solidus.io"&gt;Solidus&lt;/a&gt; did with &lt;a href="https://spree.com"&gt;Spree&lt;/a&gt;. A group of contributors got together and decided to start a new open source, e-commerce framework which started as a fork of Spree.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://solidus.io/blog/2019/07/10/governance-published.html"&gt;governance model for Solidus&lt;/a&gt; is actually quite interesting and definitely a step in the right direction based on lessons learned from Spree and Solidus' history&lt;/p&gt;

&lt;p&gt;Assuming you didn't skip any steps, you may want to post a comment in the issue you submitted initially. In there you can say that until the maintainers respond, you will be maintaining a fork of this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advice for Open Source Maintainers
&lt;/h2&gt;

&lt;p&gt;What can you do as someone who is maintaining an OSS project to make it easieron yourself? What can you do as someone who is done maintaining the projectand wants to move on? Here are some ideas based on my own experience and advice from other maintainers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Look for Co-Maintainers
&lt;/h3&gt;

&lt;p&gt;You don't have to do it alone. It's very likely that many of the users and contributors of your project would be happy to step up their commitment to co-maintain it. &lt;a href="https://opensource.guide/best-practices/#share-the-workload"&gt;You can go so much further if you build a team of co-maintainers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nobody wants to spend their holidays answering comments, reviewing pull requests, or triaging bugs. The nice thing about finding co-maintainers is that they can step up when you can't.&lt;/p&gt;

&lt;p&gt;A quick and simple way to do this is to post an issue to your repository. Another one is to post a notice at the beginning of the README. You don't have to accept all the people who are interested, but maybe some recent contributors will be interested.&lt;/p&gt;

&lt;h3&gt;
  
  
  Look for Someone to Continue Maintenance
&lt;/h3&gt;

&lt;p&gt;If you can't actively maintain the project anymore, you can update your README sharing this with your users and contributors. You can say that your project needs a new maintainer and wait for people to reach out to you.&lt;/p&gt;

&lt;p&gt;If nobody reaches out to you, then maybe they are using an alternative solution.You can update your README to mention that your project is no longer being maintained and that there are other alternatives to solve a similar problem.&lt;/p&gt;

&lt;p&gt;Finally, if you are using GitHub, you can &lt;a href="https://github.blog/2017-11-08-archiving-repositories/"&gt;archive your repository&lt;/a&gt;. This will show a warning bar to anyone who gets to your project's page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This repository has been archived by the owner. It is now read-only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Vet Potential Maintainers or Co-Maintainers
&lt;/h3&gt;

&lt;p&gt;Of course, as a responsible maintainer you don't want to let some random personon the Internet maintain your project. Trust needs to be earned. I think that's probably the most concerning part about giving up control.&lt;/p&gt;

&lt;p&gt;Do you know this person? Do you know someone who knows them? Have they been contributing to your project for years? How can you really trust them?&lt;/p&gt;

&lt;p&gt;Before you give a person permission to merge to master and publish new versions of your library, you can ask them to submit &lt;code&gt;n&lt;/code&gt; contributions to your project. That way you can see if they know what they are doing and you trust them to steer the project in the right direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Send Me a Pull Request
&lt;/h2&gt;

&lt;p&gt;Did I miss anything? Do you have any tips that could be useful to the OSS community?&lt;/p&gt;

&lt;p&gt;This article is open source and you can find it here: &lt;a href="https://github.com/fastruby/blog"&gt;https://github.com/fastruby/blog&lt;/a&gt;. So if you see something that could be improved or correct, please fork our repo and send a pull request. Thank you!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Bye bye, Medium! Hello, Jekyll 4.0! 👋🏼</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Tue, 03 Dec 2019 02:25:00 +0000</pubDate>
      <link>https://dev.to/etagwerker/bye-bye-medium-hello-jekyll-4-0-3519</link>
      <guid>https://dev.to/etagwerker/bye-bye-medium-hello-jekyll-4-0-3519</guid>
      <description>&lt;p&gt;This year Medium decided to &lt;a href="https://techcrunch.com/2019/02/27/medium-twitter-paywall/"&gt;implement a paywall&lt;/a&gt; with all their content (meaning my content, and your content, and anyone’s content published in their platform)&lt;/p&gt;

&lt;p&gt;When that happened I thought it was a good idea to leave their platform and use &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; instead. It took me almost 10 months to finally move away from Medium! This Thanksgiving break was a good time to spend a few hours migrating my content to Jekyll + &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is how I did it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I started with &lt;a href="https://fastruby.io"&gt;FastRuby.io&lt;/a&gt;’s blog’s source code (which is &lt;a href="https://github.com/fastruby/blog"&gt;open source&lt;/a&gt;). Then I followed the instructions in this article: &lt;a href="https://hackernoon.com/medium-2-md-convert-medium-posts-to-markdown-with-front-matter-c044e02c3cbb"&gt;https://hackernoon.com/medium-2-md-convert-medium-posts-to-markdown-with-front-matter-c044e02c3cbb&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I tweaked some of the content and file names. I had to massively edit file names so that Jekyll could figure out that it had to generate HTML pages for them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I migrated from Jekyll 3.0 to 4.0. Fortunately the migration was quite easy! You can see all the changes over here: &lt;a href="https://github.com/etagwerker/etagwerker.com/pull/1/files"&gt;https://github.com/etagwerker/etagwerker.com/pull/1/files&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I implemented &lt;a href="https://github.com/poole/hyde"&gt;Hyde&lt;/a&gt; and tweaked a few details to find a look &amp;amp; feel that I liked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I configured &lt;a href="https://aws.amazon.com/route53/"&gt;Route 53&lt;/a&gt; and &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; to &lt;a href="https://help.github.com/en/github/working-with-github-pages/about-custom-domains-and-github-pages#using-an-apex-domain-for-your-github-pages-site"&gt;serve the domain without &lt;code&gt;www&lt;/code&gt;&lt;/a&gt;. The nice thing about GitHub Pages is that it is simple, easy, and free for open source projects.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z1GU8M_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://etagwerker.com/assets/images/github-pages-configuration-dns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z1GU8M_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://etagwerker.com/assets/images/github-pages-configuration-dns.png" alt="GitHub's Pages DNS Settings" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the end result!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uRHs_xtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://etagwerker.com/assets/images/jekyll-end-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uRHs_xtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://etagwerker.com/assets/images/jekyll-end-result.png" alt="Screenshot of etagwerker.com using Jekyll + Hyde (Poole)" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are thinking about migrating away from Medium, Jekyll is a great alternative to have full control of your platform and content! ❤️&lt;/p&gt;

&lt;p&gt;PS: And if you want to take advantage of a great, developer-focused platform, you can cross-post all your articles to DEV! You just need to set up the right settings in your profile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Z5vELEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ixluozr33jpwiryphdsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Z5vELEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/ixluozr33jpwiryphdsp.png" alt="Screenshot for RSS import settings in dev.to" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jekyll</category>
    </item>
    <item>
      <title>Introducing Skunk: Combine Code Quality and Coverage to Calculate a Stink Score</title>
      <dc:creator>Ernesto Tagwerker (he/him)</dc:creator>
      <pubDate>Mon, 04 Nov 2019 10:00:00 +0000</pubDate>
      <link>https://dev.to/etagwerker/introducing-skunk-combine-code-quality-and-coverage-to-calculate-a-stink-score-6f4</link>
      <guid>https://dev.to/etagwerker/introducing-skunk-combine-code-quality-and-coverage-to-calculate-a-stink-score-6f4</guid>
      <description>&lt;p&gt;Two weeks ago I had the opportunity to speak at &lt;a href="https://conf.solidus.io"&gt;Solidus Conf 2019&lt;/a&gt;.I presented &lt;a href="https://speakerdeck.com/etagwerker/escaping-the-tar-pit-at-solidus-conf-2019"&gt;Escaping the Tar Pit&lt;/a&gt;for the first time and I got to talk about a few metrics that we can use toquickly &lt;a href="https://www.fastruby.io/blog/ruby/quality/code-quality-ruby-gems.html"&gt;assess code quality&lt;/a&gt;in any Ruby project.&lt;/p&gt;

&lt;p&gt;In this article I'd like to talk about &lt;a href="https://github.com/fastruby/skunk"&gt;Skunk: A Stink Score Calculator&lt;/a&gt;!I'll explain why we need it, how it works, and the roadmap for this new tool.&lt;/p&gt;

&lt;p&gt;Every month we get contacted by leads (potential clients) who want to work withus on their &lt;a href="https://fastruby.io/roadmap"&gt;Rails upgrade projects&lt;/a&gt;. Given that wehave some basic requirements for all of our new client projects, we want tocarefully analyze every project before we commit to working on it.&lt;/p&gt;

&lt;p&gt;We analyze two very important aspects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code Coverage&lt;/li&gt;
&lt;li&gt;Code Quality&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Code Coverage we like to use &lt;a href="https://www.github.com/colszowka/simplecov"&gt;SimpleCov&lt;/a&gt;.For Code Quality we like to use &lt;a href="https://github.com/whitesmith/RubyCritic"&gt;RubyCritic&lt;/a&gt;.Both tools give us a few &lt;em&gt;signals&lt;/em&gt; which tell us a story about the health of aRails application. We want to answer these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it a dumpster fire?&lt;/li&gt;
&lt;li&gt;Are we going to get ourselves stuck in the tar pit?&lt;/li&gt;
&lt;li&gt;Is it a project that is easy to maintain?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/fastruby/skunk"&gt;Skunk&lt;/a&gt; is a Ruby gem that will combine codequality metrics from &lt;a href="https://github.com/troessner/reek"&gt;Reek&lt;/a&gt;;&lt;a href="https://github.com/seattlerb/flay"&gt;Flay&lt;/a&gt;;&lt;a href="https://github.com/seattlerb/flog"&gt;Flog&lt;/a&gt;; and&lt;a href="https://github.com/colszowka/simplecov"&gt;SimpleCov&lt;/a&gt; to calculate a Stink Scorefor a file or set of files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rubygems.org/gems/skunk"&gt;Skunk&lt;/a&gt; is a library built on top of&lt;a href="https://github.com/whitesmith/rubycritic"&gt;RubyCritic&lt;/a&gt;. It uses the &lt;code&gt;cost&lt;/code&gt; valuefor each module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;RubyCritic&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnalysedModule&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cost&lt;/span&gt;
      &lt;span class="vi"&gt;@cost&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;smells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:cost&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;+&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complexity&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="no"&gt;COMPLEXITY_FACTOR&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;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cost&lt;/code&gt; is a combination of smells and complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smells: They come from static code analysis performed by Flog; Flay; and Reek.&lt;/li&gt;
&lt;li&gt;Complexity: It comes from Flog's total &lt;a href="http://wiki.c2.com/?AbcMetric"&gt;ABC metric&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After determining that the &lt;em&gt;cost&lt;/em&gt;, Skunk penalizes modules which lack code coverageby multiplying their cost by a factor directly related to the lack of coverage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;RubyCritic&lt;/span&gt;
  &lt;span class="c1"&gt;# Monkey-patches RubyCritic::AnalysedModule to add a stink_score method&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnalysedModule&lt;/span&gt;
    &lt;span class="no"&gt;PERFECT_COVERAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

    &lt;span class="c1"&gt;# Returns a numeric value that represents the stink_score of a module:&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# If module is perfectly covered, stink score is the same as the&lt;/span&gt;
    &lt;span class="c1"&gt;# `churn_times_cost`&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# If module has no coverage, stink score is a penalized value of&lt;/span&gt;
    &lt;span class="c1"&gt;# `churn_times_cost`&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# For now the stink_score is calculated by multiplying `churn_times_cost`&lt;/span&gt;
    &lt;span class="c1"&gt;# times the lack of coverage.&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# For example:&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# When `churn_times_cost` is 100 and module is perfectly covered:&lt;/span&gt;
    &lt;span class="c1"&gt;# stink_score =&amp;gt; 100&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# When `churn_times_cost` is 100 and module is not covered at all:&lt;/span&gt;
    &lt;span class="c1"&gt;# stink_score =&amp;gt; 100 * 100 = 10_000&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# When `churn_times_cost` is 100 and module is covered at 75%:&lt;/span&gt;
    &lt;span class="c1"&gt;# stink_score =&amp;gt; 100 * 25 (percentage uncovered) = 2_500&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# @return [Float]&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stink_score&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;churn_times_cost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;PERFECT_COVERAGE&lt;/span&gt;

      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;churn_times_cost&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PERFECT_COVERAGE&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After doing all these calculations, we get a Stink Score for the files we are evaluating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;skunk
running flay smells
.............
running flog smells
.............
running reek smells
.............
running complexity
.............
running attributes
.............
running churn
.............
running simple_cov
.............
New critique at file:////skunk/tmp/rubycritic/overview.html
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
| file | stink_score | churn_times_cost | churn | cost | coverage |
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
| lib/skunk/cli/commands/default.rb | 166.44 | 1.6643999999999999 | 3 | 0.5548 | 0 |
| lib/skunk/cli/application.rb | 139.2 | 1.392 | 3 | 0.46399999999999997 | 0 |
| lib/skunk/cli/command_factory.rb | 97.6 | 0.976 | 2 | 0.488 | 0 |
| &lt;span class="nb"&gt;test&lt;/span&gt;/test_helper.rb | 75.2 | 0.752 | 2 | 0.376 | 0 |
| lib/skunk/rubycritic/analysed_module.rb | 48.12 | 1.7184 | 2 | 0.8592 | 72.72727272727273 |
| &lt;span class="nb"&gt;test&lt;/span&gt;/lib/skunk/cli/commands/status_reporter_test.rb | 45.6 | 0.456 | 1 | 0.456 | 0 |
| lib/skunk/cli/commands/base.rb | 29.52 | 0.2952 | 3 | 0.0984 | 0 |
| lib/skunk/cli/commands/status_reporter.rb | 8.0 | 7.9956 | 3 | 2.6652 | 100.0 |
| &lt;span class="nb"&gt;test&lt;/span&gt;/lib/skunk/rubycritic/analysed_module_test.rb | 2.63 | 2.6312 | 2 | 1.3156 | 100.0 |
| lib/skunk.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
| lib/skunk/cli/options.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
| lib/skunk/version.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
| lib/skunk/cli/commands/help.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+

Stink Score Total: 612.31
Modules Analysed: 13
Stink Score Average: 0.47100769230769230769230769231e2
Worst Stink Score: 166.44 &lt;span class="o"&gt;(&lt;/span&gt;lib/skunk/cli/commands/default.rb&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The most important &lt;em&gt;signals&lt;/em&gt; here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Average Stink Score per module&lt;/li&gt;
&lt;li&gt;Most complex files with little to no code coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We now know where we stand. We can clearly see the state of the application interms of code coverage and project complexity. We can now answer this question: &lt;strong&gt;"Which are the most complex files with the least coverage?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can use the Stink Score to guide us in our refactoring efforts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can I pay off technical debt and invest in the future of my application?&lt;/li&gt;
&lt;li&gt;If I were to write tests to decrease the stink score, which files could Iwrite tests for?&lt;/li&gt;
&lt;li&gt;If I were to refactor some of the most complex files, which files with goodcode coverage could I refactor?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;Skunk expects you to have a &lt;code&gt;.resultset.json&lt;/code&gt; file in the coverage directorywithin the directory that you are evaluating. It uses the data within that fileto calculate the code coverage percentage for each module.&lt;/p&gt;

&lt;p&gt;That means that you will have to run your test suite with SimpleCov enabled &lt;strong&gt;before you call &lt;code&gt;skunk&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Total Stink Score is not a useful metric within a single project, as the totalwill continue to grow as you add more features to your application. It iscertainly a useful metric if you use it to &lt;em&gt;compare two projects&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Known Issues
&lt;/h2&gt;

&lt;p&gt;The calculation of the Stink Score is not 100% accurate. It is comparing amodule's code coverage and a module's complexity. It should be a method-basedcalculation: It should calculate the complexity of a method, the code coverageof the same method, then calculate the Stink Score per method.&lt;/p&gt;

&lt;p&gt;Finally, the Stink Score of a module should be the sum of all the Stink Scoresin the module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;Assessing code quality for an application shouldn't stop at the applicationlevel. The Stink Score of our application is composed by two Stink Scores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stink Score of your application&lt;/li&gt;
&lt;li&gt;Stink Score of your dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right now Skunk will only calculate Stink Score for your application code. Inthe future it should consider your dependencies as well, generating a StinkScore for each individual dependency.&lt;/p&gt;

&lt;p&gt;The best way to assess progress in your project is to keep track of the StinkScore average over time. Is that number going up? Is it going down? How muchdoes your pull request change the Stink Score average? Right now Skunk doesnot support this, so you will have to do it manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I know that "stink" is a negative word to judge an application's technical debtand it might lead you down a negative path. By all means I don't want the StinkScore to be used in a witch hunt, to point fingers at code authors, or in anegative way in your team.&lt;/p&gt;

&lt;p&gt;I seriously hope that you can use the Stink Score as the compass to move yourteam in the right direction. You should be able to use the Stink Score as acompass to gradually pay off technical debt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing tests which increase code coverage will improve the Stink Score&lt;/li&gt;
&lt;li&gt;Refactoring complex files will improve the Stink Score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skunk will show you your location in &lt;em&gt;the map of technical debt&lt;/em&gt;. It will alsoshow you a few paths to take to get to a better place. You will be able toprioritize the paths and pick one to pay off technical debt.&lt;/p&gt;

&lt;p&gt;What do you think about this new metric for technical debt? Would you use itnext time you need to evaluate legacy code?&lt;/p&gt;

&lt;p&gt;Please let me know in the comments below or come talk to me at&lt;a href="https://www.rubyconf.org"&gt;RubyConf 2019&lt;/a&gt; (I'll be speaking about&lt;a href="https://www.rubyconf.org/program#session-876"&gt;this topic at the conference&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>rubycritic</category>
      <category>codequality</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
