Techie July 2022
Introduction
Good programming practices promote readability and maintainability of the code and also reduces complexity. These coding standards enables a team to have a better overall understanding of a project, which leads to fewer errors and a reduced need for constant fixes.
It is good to learn the best practices early on to make the most out of any programming language. This section describes some of the best practices for the RoR framework.
1. Rescue from StandardError Rather Than Exception
Rescuing from Exception broadens the scope rather than narrowing it, and can have catastrophic results and make bug-hunting a pain. Exception is the root of Ruby’s exception hierarchy, so when you rescue Exception you rescue from everything, including subclasses such as SyntaxError, LoadError, and Interrupt.
By default Ruby will rescue from StandardError
If you need a variable with the exception, you could do this:
However, it is okay to rescue from Exception for logging/reporting purposes, in which case you should immediately re-raise the exception:
2. Don’t Violate The Law Of Demeter
In programming the Law Of Demeter is not really a law but a guidline that states: an entity or object should not call methods through another entity or object.
For instance, say you have 3 related models: Author, Article and Comment
Suppose you want to get information about the author related to a given review? Doing the following would work:
But using several dots is a violation of of the Law of Demeter which would have you use only one.
To avoid the multi dot syndrome, Rails provides a delegate method which helps you shorten your methods.
To achieve that, you need to delegate Author methods in Book model:
Now Book can use Author methods.
But since you’re using the methods from Review instance, you also need to delegate the methods in Review model:
If Book or Author object is nil, you will have NoMethodError raised. You avoid that by specifying allow_nil: true in delegate method.
Now you can easily use those methods from the Review instance:
NB: You could also use prefix: true which gets class name provided to :to hash and uses it as a prefix. In this case that will result in:
Not really good for this example hence why prefix: ‘book_author’ is preferable.
In other cases, you would be tempted to access information across models by chaining together methods such as @author.book.all
Again, 2 dots are too many.
You would need to create a helper method in the Author class that would achieve this for you.
Now you would be able to adhere to the design priciple by only having to use one dot to access the same information:
3. Use ? At the End of Method Name If It Is Returning Boolean Value
4. Declare Instance Variables Inside the Action
Instance variables should not be placed in private methods but rather declared inside the action. This increases readability and eliminates confusion.
5. Make Helper Methods for Views
Avoid filling the views with calculations but when it’s unavoidable, do the processing with helpers.
Don’t do this:
Do this instead:
And create a helper:
The same technique can be applied for conditional displays:
Don’t do this:
Do this instead:
And create a helper:
6. Keep it simple, stupid (KISS)
Keep it simple, stupid (KISS) is a design principle which states that designs and/or systems should be as simple as possible. In modern era the principle has evolved to have less derogatory implications and if you so wish you may also refer to is as: Keep It Short and Simple or Keep It Short and Sweet.
The easier something is to understand and use, the more likely it is to be adopted and engaged with. Simplicity should be a primary design goal to reduce complexity. It can be achieved by following the “Single Responsibility Principle” among other techniques.
7. Continuous Refactoring
Continuous improvement of a programs internal structure ensures that the product is being done according to best practice and does not degenerate to a patch work. The process should be a constant and gradual improvement to your codebase.
8. Prevent SQL Injection
Do not supply user input as a database query without escaping quotes. If the user passes a single quote in an input text, then the text after the single quote character is considered to be an SQL statement. This means that the text would have direct access to the database, putting the entire database at risk as the user might have entered malicious content.
9. Write Tests
Testing is an absolute best practice in software development. Running your Rails tests you can ensure your code adheres to the desired functionality even after some major code refactoring.
Rails tests can also simulate browser requests and thus you can test your application’s response without having to test it through your browser. Tests also acts as detailed specifications of a feature or application and as documentation for other engineers, which helps them understand your intent in an implementation.
10. Make Use of Enums
An enum is an attribute where the values map to integers in the database and can be queried by name.
Say you wanted to store the status attribute of the book object as either completed, draft or published. You may do something like this:
Which is not very elegant.
A better approach would be to define an enum for the status attribute of Book object, where the possible values are draft, completed, or published. After refactoring the code, it would look like this:
Ruby on Rails also provides a helper for updating the enum value. Instead of Book.update(status: :published), we can use: Book.published!
You can also generate a scope like so: Book.draft instead of doing Book.where(status: ‘draft’)
Lastly, you could make the scope more intuitive by adding the _prefix: true or _suffix: true option:
Thanks for reading, see you in the next one!