<?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: Fermín Molinuevo</title>
    <description>The latest articles on DEV Community by Fermín Molinuevo (@ferminmoli).</description>
    <link>https://dev.to/ferminmoli</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%2F572940%2F4258387e-c8e6-4189-9d14-8efae54399ea.png</url>
      <title>DEV Community: Fermín Molinuevo</title>
      <link>https://dev.to/ferminmoli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ferminmoli"/>
    <language>en</language>
    <item>
      <title>Code Review Best Practices: Improving Collaboration and Code Quality</title>
      <dc:creator>Fermín Molinuevo</dc:creator>
      <pubDate>Tue, 05 Mar 2024 20:07:45 +0000</pubDate>
      <link>https://dev.to/ferminmoli/code-review-best-practices-improving-collaboration-and-code-quality-4iig</link>
      <guid>https://dev.to/ferminmoli/code-review-best-practices-improving-collaboration-and-code-quality-4iig</guid>
      <description>&lt;p&gt;&lt;strong&gt;Why code reviews?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Error Detection and Bug Prevention:&lt;br&gt;
Code reviews catch errors and bugs early, preventing them from propagating into the production codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Knowledge Sharing:&lt;br&gt;
Developers gain insights into different areas of the codebase, fostering a cross-functional understanding among team members.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistency and Standards:&lt;br&gt;
Code reviews ensure that the codebase adheres to coding standards, promoting consistency and making the codebase more maintainable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collaboration and Team Building:&lt;br&gt;
Code reviews promote collaboration, contributing to a shared sense of responsibility for the overall quality of the software.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How to improve code reviews?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Regular and Timely Reviews:&lt;br&gt;
Incorporate code reviews as a standard step in the development workflow using tools like Bitbucket, GitHub, or GitLab Merge Requests to ensure timely and regular assessments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear Objectives and Scope:&lt;br&gt;
Communicate the objectives of the code review using comments and in-app discussions within the version control platform, setting the stage for a focused evaluation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automated Tools:&lt;br&gt;
Integrate automated tools like RuboCop for Ruby or ESLint for JavaScript to perform static analysis, linting, and formatting checks before the code reaches the manual review stage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Evidence:&lt;br&gt;
Provide tangible evidence showcasing the functionality and effectiveness of your code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Include screenshots of the application or relevant interfaces demonstrating the changes made by the code.&lt;/li&gt;
&lt;li&gt;Attach logs that highlight key interactions, errors, or important events during the code’s execution.&lt;/li&gt;
&lt;li&gt;Create short screencasts or videos showcasing the behavior of the code in action.&lt;/li&gt;
&lt;li&gt;Share results from unit tests to demonstrate the reliability and correctness of the code.&lt;/li&gt;
&lt;li&gt;Include performance metrics or benchmarks if relevant to showcase the efficiency of the code changes.&lt;/li&gt;
&lt;li&gt;Use descriptive captions or comments to guide reviewers through the evidence and provide context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures that the evidence is easily understandable and effectively supports the code changes being reviewed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to give feedback?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Constructive Criticism:&lt;br&gt;
Frame feedback in a constructive manner using inline comments in version control platforms, focusing on the code’s behavior and maintainability rather than personal attributes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specific and Actionable Feedback:&lt;br&gt;
Provide specific comments using tools like Bitbucket’s inline commenting feature, identifying the location of issues and suggesting concrete solutions or improvements for actionable feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Appreciate Positive Aspects:&lt;br&gt;
Acknowledge positive aspects of the code within the review platform, encouraging developers to continue incorporating good practices in their work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Which tools can I use?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Code Review Tools:&lt;br&gt;
Leverage code review tools like GitHub, GitLab, or Bitbucket to streamline the review process, allowing for comments, discussions, and version control integration.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - Github: https://github.com/features/code-review
  - GitLab: https://docs.gitlab.com/ee/user/project/merge_requests/
  - Bitbucket: https://support.atlassian.com/bitbucket-cloud/docs/- tutorial-learn-about-bitbucket-pull-requests/
  - Code rabbit (AI): https://coderabbit.ai/
  - Copilot (AI): https://github.com/features/copilot
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Checklists:&lt;br&gt;
Use checklists within the review platform to ensure that common issues, including error handling, security considerations, and performance, are consistently addressed during code reviews.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  A - Good Design:

  Evaluate the overall architecture and design choices.
  Check for adherence to design principles and patterns.
  Assess if the code aligns with the project’s architecture and doesn’t introduce unnecessary complexity.

  B — The Functionality Covers User’s Acceptance Criteria:

  Verify that the implemented functionality meets the defined user stories and acceptance criteria.
  Ensure that edge cases and potential scenarios are considered and handled appropriately.

  C — Code Cleanliness and Simplicity:

  Review the code for clarity and simplicity.
  Check if variable and method names are meaningful and self-explanatory.
  Assess if unnecessary complexity and duplication have been minimized.

  D — Avoidance of Unnecessary Future Implementations:

  Examine if the developer has avoided speculative implementations for potential future needs.
  Evaluate if the code addresses the current requirements without over-engineering.

  E — Appropriate Unit Tests:

  Confirm the presence of unit tests for critical and complex parts of the code.
  Assess if tests cover a range of scenarios, including boundary cases and potential error conditions.

  F — Quality of Tests:

  Evaluate the quality of unit tests.
  Ensure that tests are reliable, repeatable, and provide meaningful assertions.
  Check for test coverage, targeting both positive and negative scenarios.

  G — Clear and Useful Comments:

  Assess the clarity and usefulness of comments.
  Ensure that comments focus on explaining the rationale behind decisions, especially where the code might be non-intuitive.
  Verify that comments are up-to-date and not misleading.

  H — Adherence to Project Style Guides:

  Confirm that the code aligns with the project’s coding conventions and style guides.
  Check for consistent indentation, naming conventions, and formatting.
  Ensure that any deviations from the style guide are justified and documented.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Knowledge Sharing Sessions:&lt;br&gt;
Organize knowledge-sharing sessions where team members discuss interesting or challenging code snippets using collaboration tools like Google Meet, Microsoft Teams, or Zoom, fostering a culture of continuous learning and improvement.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How can I monitor them?&lt;/strong&gt;&lt;br&gt;
Utilize metrics and analytics within version control platforms to monitor the effectiveness of code reviews. Track the number of issues identified, resolution times, and overall code quality improvements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Several comments or commits may indicate that the code is too complex or the Authors would require more training.&lt;/li&gt;
&lt;li&gt;A long review time may indicate that the types of work move slower than other types and can allow you to detect opportunities to accelerate your development cycle.&lt;/li&gt;
&lt;li&gt;Few comments and approvers may indicate a lack of available team members or that the code is too complex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;
Code reviews, when conducted effectively, contribute significantly to maintaining code quality and fostering collaboration within development teams. By implementing these best practices and leveraging tools like GitHub, GitLab, and Bitbucket, teams can create a positive and constructive code review culture that contributes to the overall success of the software development process. Embrace a continuous improvement mindset, and watch as your codebase becomes more robust and your team more cohesive. Happy coding! 😃&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Clean Code Cheatsheet: A Developer’s Guide to Readable and Maintainable Code with Ruby Examples</title>
      <dc:creator>Fermín Molinuevo</dc:creator>
      <pubDate>Tue, 05 Mar 2024 20:04:07 +0000</pubDate>
      <link>https://dev.to/ferminmoli/clean-code-cheatsheet-a-developers-guide-to-readable-and-maintainable-code-with-ruby-examples-2ea4</link>
      <guid>https://dev.to/ferminmoli/clean-code-cheatsheet-a-developers-guide-to-readable-and-maintainable-code-with-ruby-examples-2ea4</guid>
      <description>&lt;p&gt;Welcome to this short Clean Code Cheatsheet — your comprehensive guide to writing clean, readable, and maintainable code, with practical examples in the Ruby programming language. Whether you’re a Ruby enthusiast or simply looking to enhance your coding practices, this cheatsheet covers essential clean code principles applicable to any language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Clean Code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Clean code is the cornerstone of effective software development. It’s about crafting code that is not only functional but also easy to understand, modify, and collaborate on. In the world of programming, code is read far more often than it is written. Clean code prioritizes readability, simplicity, and good design to minimize the long-term cost of maintaining and evolving a codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to Expect?&lt;/strong&gt;&lt;br&gt;
This cheatsheet provides actionable tips and guidelines for writing clean code, accompanied by Ruby examples. Each section covers a specific aspect of clean coding, offering insights that can be applied across various programming languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaningful Names&lt;/strong&gt;**&lt;br&gt;
Choose descriptive and expressive variable names&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
a = 10
b = 'John'
x = 15

# Good
age = 10
first_name = 'John'
number_of_students = 15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Methods&lt;/strong&gt;&lt;br&gt;
Craft concise and focused functions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
def process_data_and_output_result(input)
  # complex data processing
  # ...
  # complex result formatting
  # ...
end

# Good
def process_data(input)
  processed_data = complex_data_processing(input)
  formatted_result = format_result(processed_data)
  output_result(formatted_result)
end

def complex_data_processing(data)
  # detailed logic
end

def format_result(result)
  # detailed formatting
end

def output_result(result)
  # output logic
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Method arguments&lt;/strong&gt;&lt;br&gt;
Limit the number of arguments&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad - Passing individual parameters
def book(user, hotel)
  # ...
end

user = User.new('John')
hotel = Hotel.new('Hotel')
book(user, hotel)

# Good - Passing a class object
def book(booking_info)
  # ...
end

class BookingInfo
  attr_accessor :user, :hotel

  def initialize(user, hotel)
    @user = user
    @hotel = hotel
  end
end

user = User.new('John')
hotel = Hotel.new('Hotel')

booking_info = BookingInfo.new(user, hotel)
book(booking_info)

Constants
Create constants to avoid the hardcoding things

# Bad
if error_code == 8097
 # Handle the service unavailable error
end

# Good
SERVICE_UNAVAILABLE_ERROR_CODE = 8097

if error_code == SERVICE_UNAVAILABLE_ERROR_CODE
  # Handle the service unavailable error
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mental mapping&lt;/strong&gt;&lt;br&gt;
Avoid the need to keep things on our mind&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
u_n = 'John'
users = ['John', 'Peter']

users.each do |u|
  first_operation(u)
  second_operation
  ..
  n_operation(u)
end

# Good - Using a descriptive loop variable
target_user_name = 'John'
users = ['John', 'Peter']

users.each do |current_user|
  first_operation(current_user)
  second_operation
  # ...
  n_operation(current_user)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt;&lt;br&gt;
Use comments sparingly, focusing on why, not what:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad 
# Increment i by 1 
i += 1  

# Good 
i += 1  # Increment loop counter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Formatting&lt;br&gt;
Follow Code standard formatting conventions.&lt;/p&gt;

&lt;p&gt;If you are working with Ruby, try to follow the standard formatting conventions. Refer to the RubyStyle Guide for comprehensive guidelines.&lt;/p&gt;

&lt;p&gt;Utilize tools like RuboCop to enforce and maintain the code style&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
def my_method(param1, param2)
param1 + param2
end

# Good
def my_method(param1, param2)
  param1 + param2
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;br&gt;
Use exceptions for error handling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
def divide(a, b)
  if b == 0
    puts 'Cannot divide by zero!'
    return
  end
  a / b
end

# Good
class DivisionByZeroError &amp;lt; StandardError
  def initialize(msg = 'Cannot divide by zero!')
    super
  end
end

def divide(a, b)
  raise DivisionByZeroError if b.zero?
  a / b
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Duplicated Code&lt;/strong&gt;&lt;br&gt;
Eliminate redundancy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
def calculate_area_of_circle(radius)
  Math::PI * radius * radius
end

def calculate_volume_of_sphere(radius)
  (4 / 3) * Math::PI * radius * radius * radius
end

# Good
def calculate_area_of_circle(radius)
  Math::PI * radius * radius
end

def calculate_volume_of_sphere(radius)
  (4 / 3.0) * calculate_area_of_circle(radius) * radius
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Encapsulate conditionals&lt;/strong&gt;&lt;br&gt;
Always aim for clear and self-explanatory method names to improve the understanding of the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
if user_signed_in? &amp;amp;&amp;amp; admin_user?
  # ...
end

# Good
def admin_access?(user)
  user_signed_in? &amp;amp;&amp;amp; admin_user?(user)
end

if admin_access?(current_user)
  # ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avoid negative conditionals&lt;/strong&gt;&lt;br&gt;
Writing code with positive conditionals instead of negative ones can greatly enhance code readability and maintainability. Code that is expressed in a positive manner tends to be more straightforward and easier for others (or even yourself) to understand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
unless !user.active &amp;amp;&amp;amp; !user.admin?
  # Perform actions for inactive non-admin users
end

# Good
if user.inactive? &amp;amp;&amp;amp; !user.admin?
  # Perform actions for inactive non-admin users
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using Polymorphism to Improve Switch Statements&lt;/strong&gt;&lt;br&gt;
Switch statements can become hard to maintain and extend as the number of cases grows. Leveraging polymorphism provides a more flexible and scalable alternative. Let’s explore how to improve a switch statement using polymorphism with an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad

class Shape
  def draw
    case type
    when :circle
      draw_circle
    when :square
      draw_square
    when :triangle
      draw_triangle
    else
      raise 'Unsupported shape!'
    end
  end

private

  def draw_circle
    # draw circle logic
  end

  def draw_square
    # draw square logic
  end

  def draw_triangle
    # draw triangle logic
  end
end

shape = Shape.new(:circle)
shape.draw


# Good

class Shape
  def draw
    raise NotImplementedError, 'Subclasses must implement this method'
  end
end

class Circle &amp;lt; Shape
  def draw
    # draw circle logic
  end
end

class Square &amp;lt; Shape
  def draw
    # draw square logic
  end
end

class Triangle &amp;lt; Shape
  def draw
    # draw triangle logic
  end
end

shape = Circle.new
shape.draw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Objects and Data Structures&lt;/strong&gt;&lt;br&gt;
Encapsulate data with behavior in classes, and use data structures for simple storage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
user_data = { name: 'Alice', age: 25 }

# Good
class User
  attr_accessor :name, :age
  def initialize(name, age)
    @name = name
    @age = age
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SOLID Principles&lt;/strong&gt;&lt;br&gt;
Follow SOLID principles for designing maintainable and scalable systems&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt;&lt;br&gt;
The Single Responsibility Principle states that a class should have only one reason to change. In this example, the Calculator class has a single responsibility, which is to perform addition. If there are changes related to addition, the Calculator class is the only one that needs modification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Calculator
  def add(a, b)
    a + b
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Open/Closed Principle (OCP)&lt;/strong&gt;&lt;br&gt;
It states that a class should be open for extension but closed for modification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Shape
  def area
    raise NotImplementedError, 'Subclasses must implement this method'
  end
end

class Circle &amp;lt; Shape
  def area(radius)
    Math::PI * radius * radius
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Shape class is open for extension by allowing new shapes to be added through subclasses (like Circle) without modifying the existing Shape class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Liskov Substitution Principle (LSP)&lt;/strong&gt;&lt;br&gt;
The Liskov Substitution Principle states that objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Shape
  def area
    raise NotImplementedError, 'Subclasses must implement this method'
  end
end

class Rectangle &amp;lt; Shape
  attr_accessor :width, :height

  def area
    width * height
  end
end

class Square &amp;lt; Shape
  attr_accessor :side

  def area
    side * side
  end
end

def calculate_total_area(shapes)
  total_area = 0
  shapes.each { |shape| total_area += shape.area }
  total_area
end

rectangle = Rectangle.new
rectangle.width = 5
rectangle.height = 10

square = Square.new
square.side = 7

shapes = [rectangle, square]

puts "Total area: #{calculate_total_area(shapes)}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Interface Segregation Principle (ISP)&lt;/strong&gt; &lt;br&gt;
The Interface Segregation Principle states that a class should not be forced to implement interfaces it does not use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad - Interface with multiple methods
module Employee
  def work
    # work logic
  end

  def manage
    # management logic
  end
end

class Worker
  include Employee

  # Worker needs to implement both work and manage, even if it doesn't manage
end

class Manager
  include Employee

  # Manager needs to implement both work and manage, even if it doesn't perform the regular work
end

# Good - Separate interfaces for work and management
module Workable
  def work
    # work logic
  end
end

module Managable
  def manage
    # management logic
  end
end

class Worker
  include Workable

  # Worker only includes the Workable interface, as it doesn't manage
end

class Manager
  include Workable
  include Managable

  # Manager includes both interfaces, as it performs both work and management
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, each class has a specific interface relevant to its responsibilities. Workers implement the work interface, while Managers implement the manage interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Inversion Principle (DIP)&lt;/strong&gt;&lt;br&gt;
The Dependency Inversion Principle states that high-level modules should not depend on low-level modules, but both should depend on abstractions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class LightBulb
  def turn_on
    # turn on logic
  end
end

class Switch
  def initialize(device)
    @device = device
  end
  def operate
    @device.turn_on
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Switch class depends on the abstraction (LightBulb) rather than the specific implementation. This allows for flexibility and easier maintenance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Descriptive Test Names: To help developers understand the purpose and expected behavior of each test case without diving into the details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad
def test_method
  # ...
end

# Good
def test_user_authentication_success
  # ...
end

**Explicit assertions**
Use explicit assertions that convey the expected outcome of the test, reducing ambiguity and making it clear what the test is checking.

# Bad
assert_equal true, user.authenticate('password')

# Good
assert user.authenticate('password'), 'User authentication failed'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This cheatsheet provides a foundation for writing clean code in any programming language, using Ruby as a practical example. Dive into each section for more detailed guidance and examples. Let’s make our code not only functional but a joy to read and maintain.&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Clean Code Cheatsheet: A Developer’s Guide to Readable and Maintainable Code with Ruby Examples</title>
      <dc:creator>Fermín Molinuevo</dc:creator>
      <pubDate>Tue, 05 Mar 2024 19:55:33 +0000</pubDate>
      <link>https://dev.to/ferminmoli/clean-code-cheatsheet-a-developers-guide-to-readable-and-maintainable-code-with-ruby-examples-4485</link>
      <guid>https://dev.to/ferminmoli/clean-code-cheatsheet-a-developers-guide-to-readable-and-maintainable-code-with-ruby-examples-4485</guid>
      <description>&lt;p&gt;Welcome to this short Clean Code Cheatsheet — your comprehensive guide to writing clean, readable, and maintainable code, with practical examples in the Ruby programming language. Whether you’re a Ruby enthusiast or simply looking to enhance your coding practices, this cheatsheet covers essential clean code principles applicable to any language.&lt;/p&gt;

&lt;p&gt;Why Clean Code?&lt;br&gt;
Clean code is the cornerstone of effective software development. It’s about crafting code that is not only functional but also easy to understand, modify, and collaborate on. In the world of programming, code is read far more often than it is written. Clean code prioritizes readability, simplicity, and good design to minimize the long-term cost of maintaining and evolving a codebase.&lt;/p&gt;

&lt;p&gt;What to Expect&lt;br&gt;
This cheatsheet provides actionable tips and guidelines for writing clean code, accompanied by Ruby examples. Each section covers a specific aspect of clean coding, offering insights that can be applied across various programming languages.&lt;/p&gt;

&lt;p&gt;Meaningful Names&lt;br&gt;
Choose descriptive and expressive variable names&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
a = 10&lt;br&gt;
b = 'John'&lt;br&gt;
x = 15&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;age = 10&lt;br&gt;
first_name = 'John'&lt;br&gt;
number_of_students = 15`&lt;/p&gt;

&lt;p&gt;Methods&lt;br&gt;
Craft concise and focused functions&lt;br&gt;
`&lt;/p&gt;

&lt;h1&gt;
  
  
  Bad
&lt;/h1&gt;

&lt;p&gt;def process_data_and_output_result(input)&lt;br&gt;
  # complex data processing&lt;br&gt;
  # ...&lt;br&gt;
  # complex result formatting&lt;br&gt;
  # ...&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;def process_data(input)&lt;br&gt;
  processed_data = complex_data_processing(input)&lt;br&gt;
  formatted_result = format_result(processed_data)&lt;br&gt;
  output_result(formatted_result)&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def complex_data_processing(data)&lt;br&gt;
  # detailed logic&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def format_result(result)&lt;br&gt;
  # detailed formatting&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def output_result(result)&lt;br&gt;
  # output logic&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Method arguments&lt;br&gt;
Limit the number of arguments&lt;/p&gt;

&lt;p&gt;`# Bad - Passing individual parameters&lt;br&gt;
def book(user, hotel)&lt;br&gt;
  # ...&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;user = User.new('John')&lt;br&gt;
hotel = Hotel.new('Hotel')&lt;br&gt;
book(user, hotel)&lt;/p&gt;

&lt;h1&gt;
  
  
  Good - Passing a class object
&lt;/h1&gt;

&lt;p&gt;def book(booking_info)&lt;br&gt;
  # ...&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class BookingInfo&lt;br&gt;
  attr_accessor :user, :hotel&lt;/p&gt;

&lt;p&gt;def initialize(user, hotel)&lt;br&gt;
    @user = user&lt;br&gt;
    @hotel = hotel&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;user = User.new('John')&lt;br&gt;
hotel = Hotel.new('Hotel')&lt;/p&gt;

&lt;p&gt;booking_info = BookingInfo.new(user, hotel)&lt;br&gt;
book(booking_info)`&lt;/p&gt;

&lt;p&gt;Constants&lt;br&gt;
Create constants to avoid the hardcoding things&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
if error_code == 8097&lt;br&gt;
 # Handle the service unavailable error&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;SERVICE_UNAVAILABLE_ERROR_CODE = 8097&lt;/p&gt;

&lt;p&gt;if error_code == SERVICE_UNAVAILABLE_ERROR_CODE&lt;br&gt;
  # Handle the service unavailable error&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Mental mapping&lt;br&gt;
Avoid the need to keep things on our mind&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
u_n = 'John'&lt;br&gt;
users = ['John', 'Peter']&lt;/p&gt;

&lt;p&gt;users.each do |u|&lt;br&gt;
  first_operation(u)&lt;br&gt;
  second_operation&lt;br&gt;
  ..&lt;br&gt;
  n_operation(u)&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good - Using a descriptive loop variable
&lt;/h1&gt;

&lt;p&gt;target_user_name = 'John'&lt;br&gt;
users = ['John', 'Peter']&lt;/p&gt;

&lt;p&gt;users.each do |current_user|&lt;br&gt;
  first_operation(current_user)&lt;br&gt;
  second_operation&lt;br&gt;
  # ...&lt;br&gt;
  n_operation(current_user)&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Comments&lt;br&gt;
Use comments sparingly, focusing on why, not what:&lt;/p&gt;

&lt;p&gt;`# Bad &lt;/p&gt;

&lt;h1&gt;
  
  
  Increment i by 1
&lt;/h1&gt;

&lt;p&gt;i += 1  &lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;i += 1  # Increment loop counter`&lt;/p&gt;

&lt;p&gt;Formatting&lt;br&gt;
Follow Code standard formatting conventions.&lt;/p&gt;

&lt;p&gt;If you are working with Ruby, try to follow the standard formatting conventions. Refer to the RubyStyle Guide for comprehensive guidelines.&lt;/p&gt;

&lt;p&gt;Utilize tools like RuboCop to enforce and maintain the code style&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
def my_method(param1, param2)&lt;br&gt;
result = param1 + param2&lt;br&gt;
return result&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;def my_method(param1, param2)&lt;br&gt;
  result = param1 + param2&lt;br&gt;
  return result&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Error Handling&lt;br&gt;
Use exceptions for error handling.&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
def divide(a, b)&lt;br&gt;
  if b == 0&lt;br&gt;
    puts 'Cannot divide by zero!'&lt;br&gt;
    return&lt;br&gt;
  end&lt;br&gt;
  a / b&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;class DivisionByZeroError &amp;lt; StandardError&lt;br&gt;
  def initialize(msg = 'Cannot divide by zero!')&lt;br&gt;
    super&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def divide(a, b)&lt;br&gt;
  raise DivisionByZeroError if b.zero?&lt;br&gt;
  a / b&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Duplicated Code&lt;br&gt;
Eliminate redundancy&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
def calculate_area_of_circle(radius)&lt;br&gt;
  Math::PI * radius * radius&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def calculate_volume_of_sphere(radius)&lt;br&gt;
  (4 / 3) * Math::PI * radius * radius * radius&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;def calculate_area_of_circle(radius)&lt;br&gt;
  Math::PI * radius * radius&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def calculate_volume_of_sphere(radius)&lt;br&gt;
  (4 / 3.0) * calculate_area_of_circle(radius) * radius&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Encapsulate conditionals&lt;br&gt;
Always aim for self-explanatory method names to improve the understanding of the code.&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
if user_signed_in? &amp;amp;&amp;amp; admin_user?&lt;br&gt;
  # ...&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;def admin_access?(user)&lt;br&gt;
  user_signed_in? &amp;amp;&amp;amp; admin_user?(user)&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;if admin_access?(current_user)&lt;br&gt;
  # ...&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Avoid negative conditionals&lt;br&gt;
Writing code with positive conditionals instead of negative ones can greatly enhance code readability and maintainability. Code that is expressed in a positive manner tends to be more straightforward and easier for others (or even yourself) to understand.&lt;/p&gt;

&lt;p&gt;`# Bad&lt;br&gt;
unless !user.active &amp;amp;&amp;amp; !user.admin?&lt;br&gt;
  # Perform actions for inactive non-admin users&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;if user.inactive? &amp;amp;&amp;amp; !user.admin?&lt;br&gt;
  # Perform actions for inactive non-admin users&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Using Polymorphism to Improve Switch Statements&lt;br&gt;
Switch statements can become hard to maintain and extend as the number of cases grows. Leveraging polymorphism provides a more flexible and scalable alternative. Let’s explore how to improve a switch statement using polymorphism with an example.&lt;/p&gt;

&lt;p&gt;`# Bad&lt;/p&gt;

&lt;p&gt;class Shape&lt;br&gt;
  def draw&lt;br&gt;
    case type&lt;br&gt;
    when :circle&lt;br&gt;
      draw_circle&lt;br&gt;
    when :square&lt;br&gt;
      draw_square&lt;br&gt;
    when :triangle&lt;br&gt;
      draw_triangle&lt;br&gt;
    else&lt;br&gt;
      raise 'Unsupported shape!'&lt;br&gt;
    end&lt;br&gt;
  end&lt;/p&gt;

&lt;p&gt;private&lt;/p&gt;

&lt;p&gt;def draw_circle&lt;br&gt;
    # draw circle logic&lt;br&gt;
  end&lt;/p&gt;

&lt;p&gt;def draw_square&lt;br&gt;
    # draw square logic&lt;br&gt;
  end&lt;/p&gt;

&lt;p&gt;def draw_triangle&lt;br&gt;
    # draw triangle logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;shape = Shape.new(:circle)&lt;br&gt;
shape.draw&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;class Shape&lt;br&gt;
  def draw&lt;br&gt;
    raise NotImplementedError, 'Subclasses must implement this method'&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Circle &amp;lt; Shape&lt;br&gt;
  def draw&lt;br&gt;
    # draw circle logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Square &amp;lt; Shape&lt;br&gt;
  def draw&lt;br&gt;
    # draw square logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Triangle &amp;lt; Shape&lt;br&gt;
  def draw&lt;br&gt;
    # draw triangle logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;shape = Circle.new&lt;br&gt;
shape.draw&lt;br&gt;
Objects and Data Structures&lt;br&gt;
Encapsulate data with behavior in classes, and use data structures for simple storage&lt;/p&gt;

&lt;h1&gt;
  
  
  Bad
&lt;/h1&gt;

&lt;p&gt;user_data = { name: 'Alice', age: 25 }&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;class User&lt;br&gt;
  attr_accessor :name, :age&lt;br&gt;
  def initialize(name, age)&lt;br&gt;
    &lt;a class="mentioned-user" href="https://dev.to/name"&gt;@name&lt;/a&gt; = name&lt;br&gt;
    @age = age&lt;br&gt;
  end&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;SOLID Principles&lt;br&gt;
Follow SOLID principles for designing maintainable and scalable systems&lt;/p&gt;

&lt;p&gt;Single Responsibility Principle (SRP): The Single Responsibility Principle states that a class should have only one reason to change. In this example, the Calculator class has a single responsibility, which is to perform addition. If there are changes related to addition, the Calculator class is the only one that needs modification.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;class Calculator&lt;br&gt;
  def add(a, b)&lt;br&gt;
    a + b&lt;br&gt;
  end&lt;br&gt;
end&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open/Closed Principle (OCP) : It states that a class should be open for extension but closed for modification.&lt;/p&gt;

&lt;p&gt;`class Shape&lt;br&gt;
  def area&lt;br&gt;
    raise NotImplementedError, 'Subclasses must implement this method'&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Circle &amp;lt; Shape&lt;br&gt;
  def area(radius)&lt;br&gt;
    Math::PI * radius * radius&lt;br&gt;
  end&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;The Shape class is open for extension by allowing new shapes to be added through subclasses (like Circle) without modifying the existing Shape class.&lt;/p&gt;

&lt;p&gt;Liskov Substitution Principle (LSP): The Liskov Substitution Principle states that objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program.&lt;/p&gt;

&lt;p&gt;`class Shape&lt;br&gt;
  def area&lt;br&gt;
    raise NotImplementedError, 'Subclasses must implement this method'&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Rectangle &amp;lt; Shape&lt;br&gt;
  attr_accessor :width, :height&lt;/p&gt;

&lt;p&gt;def area&lt;br&gt;
    width * height&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Square &amp;lt; Shape&lt;br&gt;
  attr_accessor :side&lt;/p&gt;

&lt;p&gt;def area&lt;br&gt;
    side * side&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;def calculate_total_area(shapes)&lt;br&gt;
  total_area = 0&lt;br&gt;
  shapes.each { |shape| total_area += shape.area }&lt;br&gt;
  total_area&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;rectangle = Rectangle.new&lt;br&gt;
rectangle.width = 5&lt;br&gt;
rectangle.height = 10&lt;/p&gt;

&lt;p&gt;square = Square.new&lt;br&gt;
square.side = 7&lt;/p&gt;

&lt;p&gt;shapes = [rectangle, square]&lt;/p&gt;

&lt;p&gt;puts "Total area: #{calculate_total_area(shapes)}"`&lt;/p&gt;

&lt;p&gt;Interface Segregation Principle (ISP): The Interface Segregation Principle states that a class should not be forced to implement interfaces it does not use.&lt;/p&gt;

&lt;p&gt;`# Bad - Interface with multiple methods&lt;br&gt;
module Employee&lt;br&gt;
  def work&lt;br&gt;
    # work logic&lt;br&gt;
  end&lt;/p&gt;

&lt;p&gt;def manage&lt;br&gt;
    # management logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Worker&lt;br&gt;
  include Employee&lt;/p&gt;

&lt;p&gt;# Worker needs to implement both work and manage, even if it doesn't manage&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Manager&lt;br&gt;
  include Employee&lt;/p&gt;

&lt;p&gt;# Manager needs to implement both work and manage, even if it doesn't perform the regular work&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good - Separate interfaces for work and management
&lt;/h1&gt;

&lt;p&gt;module Workable&lt;br&gt;
  def work&lt;br&gt;
    # work logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;module Managable&lt;br&gt;
  def manage&lt;br&gt;
    # management logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Worker&lt;br&gt;
  include Workable&lt;/p&gt;

&lt;p&gt;# Worker only includes the Workable interface, as it doesn't manage&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Manager&lt;br&gt;
  include Workable&lt;br&gt;
  include Managable&lt;/p&gt;

&lt;p&gt;# Manager includes both interfaces, as it performs both work and management&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;Here, each class has a specific interface relevant to its responsibilities. Workers implement the work interface, while Managers implement the manage interface.&lt;/p&gt;

&lt;p&gt;Dependency Inversion Principle (DIP): The Dependency Inversion Principle states that high-level modules should not depend on low-level modules, but both should depend on abstractions.&lt;br&gt;
`&lt;br&gt;
class LightBulb&lt;br&gt;
  def turn_on&lt;br&gt;
    # turn on logic&lt;br&gt;
  end&lt;br&gt;
end&lt;/p&gt;

&lt;p&gt;class Switch&lt;br&gt;
  def initialize(device)&lt;br&gt;
    @device = device&lt;br&gt;
  end&lt;br&gt;
  def operate&lt;br&gt;
    @device.turn_on&lt;br&gt;
  end&lt;br&gt;
end`&lt;/p&gt;

&lt;p&gt;he Switch class depends on the abstraction (LightBulb) rather than the specific implementation. This allows for flexibility and easier maintenance.&lt;/p&gt;

&lt;p&gt;Testing&lt;br&gt;
Descriptive Test Names: To help developers understand the purpose and expected behavior of each test case without diving into the details.&lt;br&gt;
`&lt;/p&gt;

&lt;h1&gt;
  
  
  Bad
&lt;/h1&gt;

&lt;p&gt;def test_method&lt;br&gt;
  # ...&lt;br&gt;
end&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;def test_user_authentication_success&lt;br&gt;
  # ...&lt;br&gt;
end&lt;br&gt;
Explicit assertions: Use explicit assertions that convey the expected outcome of the test, reducing ambiguity and making it clear what the test is checking.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bad
&lt;/h1&gt;

&lt;p&gt;assert_equal true, user.authenticate('password')&lt;/p&gt;

&lt;h1&gt;
  
  
  Good
&lt;/h1&gt;

&lt;p&gt;assert user.authenticate('password'), 'User authentication failed'`&lt;/p&gt;

&lt;p&gt;This cheatsheet provides a foundation for writing clean code in any programming language, using Ruby as a practical example. Dive into each section for more detailed guidance and examples. Let’s make our code not only functional but a joy to read and maintain.&lt;/p&gt;

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

</description>
    </item>
  </channel>
</rss>
