Clean Code Ruby – Methods

Tram Ho

Continuing part 1 on Variables, today's article will cover how to clean code in a method. Invite you to read offline

Parameter input (ideally 2 or less)

Limiting the number of parameters passed is extremely important because it makes testing your method easier. Having more than three parameters will result in a composite explosion in which you have to test tons of different cases with each separate argument.

One or two arguments are ideal, so avoid three arguments if possible. Any function more than that should be reviewed. Usually, if you have more than two arguments, your method is trying to handle too much logic. In case this is not the case, most of us can use a higher-level object as the argument. Or you may pass data to the method using instance variables.

Because Ruby allows you to create objects quickly, without the need for multiple boilerplate classes, you can use an object if you find yourself needing many arguments. The common pattern in Ruby is to use hash arguments.

To clarify the properties that the method expects, you can use the keyword argument syntax (introduced in Ruby 2.1). This method has several advantages:

  1. When someone looks at the method signature, it immediately knows which properties are being used.
  2. If a required keyword argument is missing, Ruby issues a useful ArgumentError telling us which arguments we must pass.

Bad:

Good:

Methods should do only one thing

This is the most important rule in software engineering. When methods do more than one thing, they are harder to compose and test. When you can isolate a method with only one action, they can be easily refactored and your code will be much cleaner.

Bad:

Good:

The name of the method must describe its effect.

The methods that are named will add to the difficulty of the reviewer to evaluate the best use of the methods and can fool the reviewer in the worst case. Try to grasp the correct intent when naming the method.

Bad:

Good:

Methods should only have one level of abstraction

When you have more than one level of abstraction, your methods often do too much. Dividing methods leads to easier reuse and testing. Moreover, methods should decrease with abstraction level: a very abstract method will call less abstract methods, etc.

Bad:

Good:

Delete duplicate code

Do your best to avoid code duplication. Duplicate code is extremely bad because that means there is more than one place to change if you need to change some logic.

Imagine if you ran a restaurant and you tracked your inventory: all tomatoes, onions, garlic, spices, etc. If you have multiple lists where you keep it, then all The whole must be updated when you serve a dish with tomatoes in them. If you only have one listing, only one place to update!

Usually, you have duplicate code because you have two or more slightly different things, that have a lot in common, but their differences force you to have two or more separate methods that do many of the same things. Eliminating duplicate code means creating an abstraction that can handle this set of different things with just one method / module / class.

Proper abstraction is important, which is why you should follow the SOLID principles outlined in the Classes section. Wrong abstractions can be worse than duplicate code, so be careful!

Bad:

Good:

Do not use flags as method parameters

Flags tell your users that this method does more than one thing. Methods should do only one thing. Separate your methods if they follow different code paths based on boolean.

Bad:

Good:

Avoid side effects (part 1)

One method of generating side effects if it does anything more is to take values ​​and / or return values. A side effect could be writing to a file, modifying some global variables, or accidentally passing all your money to a stranger.

The main point is to avoid common pitfalls such as sharing state between objects without any structure, using mutable data types that can be written to anything and not set. Focus on where your side effects are occurring. If you can do this, you will be happier than the majority of other programmers.

Bad:

Good:

Avoid side effects (part 2)

In Ruby, everything is an object and everything is passed by value, but these values ​​are references to objects. In the case of objects and arrays, if your method makes changes in the shopping cart array, for example, by adding an item to purchase, any other methods that use that shopping cart array will be affected by this addition. Imagine a bad situation:

The user clicks "Buy", that button calls a purchase method and generates a request and sends the shopping cart array to the server. Due to a bad network connection, the purchase method must keep trying the request again. Now, what if, in the meantime, users accidentally clicked the "Add to Cart" button on an item they didn't really want before the network request started? If that happens and the network request begins, then that purchase method will send the item accidentally added because it has a reference to the shopping cart array that the add_item_to_cart method modified by adding an unwanted item.

A great solution is for add_item_to_cart to always make a copy of the cart, edit it, and return the copy. This ensures that no other methods referencing the shopping cart will be affected by any changes.

There are two notes to mention this method:

  1. There may be cases where you really want to change the input objects, but when you apply and practice this programming method, you will find that those cases are quite rare. Most things can be refactored with no side effects!
  2. Cloning large objects can be very costly in performance. Fortunately, this is not a big deal in practice because there are great gems that allow this programming method to be as fast and as low-memory as you can manually copy objects and arrays.

Bad:

Good:

Functional programming is preferred over imperative programming

Ruby is not a functional language in Haskell's way, but it is capable of doing that. Functional languages ​​are cleaner and easier to test. Support this programming style when you can.

Bad:

Good:

Packaging conditions

Bad:

Good:

Avoid the opposite conditions

Bad:

Good:

Avoid the conditions

This seems to be an impossible task. When hearing this for the first time, most people say, "how can I do anything without if?" The answer is that you can use polymorphism to achieve the same task in many cases. The second question is often "great, but why would I want to do that?" The answer is a previously clean code concept we have learned: a method should only do one thing. When you have classes and methods that have if statements, you're telling your users that your method does more than one thing. Remember, just do one thing.

Bad:

Good:

Avoid type-checking (part 1)

Ruby is a dynamic language, which means that your methods can accept any type of argument. Sometimes you get stuck with this freedom and the type checking in your method becomes fascinating. There are many ways to avoid having to do this. The first thing to consider is the consistent API.

Bad:

Good:

Avoid type-checking (part 2)

If you are working with basic values ​​like strings and integers and you can't use polymorphism but you still feel the need to type check, you should consider using contracts.ruby .

Bad:

Good:

Delete unused code

Dead codes are as bad as duplicate codes. There is no reason to keep it in your code base. If it is not called, remove it! It will still be safe in your version history if you still need it.

Bad:

Good:

REFERENCES

https://github.com/uohzxela/clean-code-ruby#methods

Share the news now

Source : Viblo