here are our best practices when it comes to ruby and on rails.
We only use spaces for indentation rather than hard tabs.
We prefer two-space indents.
# bad
class Car
def initialize(params)
end
end
# good
class Car
def initialize(params)
end
end
We prefer to neatly stack long method arguments.
# bad
class Car
def self.create(brand_id, brand_name, manufacturer_year, chassis_type,
rubber_type, number_of_doors, transmition_type, country_of_origin)
...
end
end
# good
class Car
def self.create(brand_id,
brand_name,
manufacturer_year,
chassis_type,
rubber_type,
number_of_doors,
transmition_type,
country_of_origin)
...
end
end
# good
class Car
def self.create(
brand_id,
brand_name,
manufacturer_year,
chassis_type,
rubber_type,
number_of_doors,
transmition_type,
country_of_origin
)
...
end
end
We prefer to properly indent Multi-line boolean statements with indentation.
# bad
def can_race?(car)
Fia::CarStandards.check_qualification?(car) &&
is_fuel_check_passed? &&
is_with_wheels?
end
# good
def can_race?(car)
Fia::CarStandards.check_qualification?(car) &&
is_fuel_check_passed? &&
is_with_wheels?
end
# bad
case color
when 'red'
puts 'ferrari'
when 'blue'
puts 'ford'
when 'black'
puts 'nissan'
else
puts 'just a car'
end
# good
case color
when 'red'
puts 'ferrari'
when 'blue'
puts 'ford'
when 'black'
puts 'nissan'
else
'just a car'
end
# bad
result = if cool?
do_something_cool
else
do_something_uncool
end
# good
result =
if cool?
do_something_cool
else
do_something_uncool
end
We use if modifiers if the condition can fit within one line else, we avoid using it
# bad
some_very_long_statement_about_coding_and_managing_states(some_very_long_variable_naming_convention) if valid?
# good
if valid?
some_very_long_statement_about_coding_and_managing_states(some_very_long_variable_naming_convention)
end
# bad
Car.create(params).add_detail.select_time_compound.race
# good
Car
.create(params)
.add_detail
.select_time_compound
.race
We use single empty line to terminate method definitions.
# bad
def create_drink(raw_ingredients)
prepared_ingredients = init_ingredients(raw_ingredients)
drink = mix(prepared_ingredients)
garnish_drink(drink)
end
def init_ingredients(ingredients)
...
end
def mix_ingredients(ingredients)
...
end
def garnish_drink(drink)
...
end
# good
def create_drink(raw_ingredients)
prepared_ingredients = init_ingredients(raw_ingredients)
drink = mix(prepared_ingredients)
garnish_drink(drink)
end
def init_ingredients(ingredients)
...
end
def mix_ingredients(ingredients)
...
end
def garnish_drink(drink)
...
end
We use single empty line to terminate declartion of accessors.
# bad
class Car
attr_reader :brand
def initialize
...
end
end
# good
class Car
attr_reader :brand
def initialize
...
end
end
We use single empty line to terminate declartion of privacy policies.
# bad
class Car
def initialize
...
end
private
def tire_compound
...
end
end
# good
class Car
def initialize
...
end
private
def tire_compound
...
end
end
We avoid commas after the last parameter in a method call.
# bad
def create(brand_id, brand_name, manufacturer_year,)
...
end
# bad
def create(brand_id, brand_name, manufacturer_year)
...
end
We use "backslashes" as a point of continuation for long strings.
# good
long_string = 'The quick brown fox jumps over the lazy dog' \
' cat, elephant, tiger, goose, goat, mouse' \
' human, and alien.'
For methods that are expecting boolean as a return value, we use "?" as a suffix
# bad
def race_worthy(car)
...
end
# good
def race_worthy?(car)
...
end
For methods that are implying that it will modify something, we use "!" as a suffix
# bad
class Car
def retire(car)
car.destroy!
end
end
# good
class Car
def retire!(car)
car.destroy!
end
end
We avoid using prefixes such as "is, does or can" but we properly allot a meaningful adjective.
# bad
def can_race?(car)
...
end
def is_aerodynamic?(car)
...
end
# good
def race_worthy?(car)
...
end
def aerodynamic?(car)
...
end
We use "_" for unused variables
# bad
def get_driver_license(driver)
personal_data, license = register_driver(driver)
return license
end
# good
get_driver_license(driver)
_personal_data, license = register_driver(driver)
return license
end
We definitely don't use for loop, not unless we had no choice, but instead use Ruby's array of iterators
# bad
numbers = [1, 2, 3]
for number in numbers do
puts number + 1
end
# good
numbers = [1, 2, 3]
numbers.each {|number| number + 1}
We use ternary operators in place of single if else statments
# bad
result = if condition then do_something else do_something_else end
# good
result = condition ? do_something : do_something_else end
Terneries are not meant to be nested. We fix this by introducing a layer of single if else statement
# bad
condition then (nested_condition ? nested_do_something : do_something) else do_something_else end
# good
if condition
nested_condition ? nested_do_something : do_something
else
do_something_else
end
We avoid nested conditionals as this could be prove to be difficult to read. In these cases, we prefer to use guard clauses.
# bad
def prepare_car(car)
if car
install_tires(car)
if car.soft_compound_tires?
set_stop_strategy(2)
else
set_stop_strategy(1)
end
end
end
# bad
def prepare_car(car)
return if car.blank?
install_tires(car)
return set_stop_strategy(2) if car.soft_compound_tires?
set_stop_strategy(1)
end
We avoid using chained "&" but we replace it with check instead.
# bad
driver&.address&.zip_code
# good
driver && driver.address&.zip_code
Or we can use delegation
# good
class Driver
def zip_code
address&.zip_code
end
end
We seldom use positional arguments, but in place we use keyword arguments.
# bad
def officiate_race(drivers, teams = [], cars = [], country = '', race_date = Time.now)
...
end
# good
def officiate_race(drivers, teams: [], cars: [], country: '', race_date: Time.now)
...
end
Or if keyword arguments are not yet available, just use options hash instead
# good
def officiate_race(drivers, options)
options = {
teams: [],
cars: [],
country: '',
race_date: Time.now
}.merge(options)
...
end
There are no such thing as constants ni Ruby as these so called constants are mutable. In order to workaround this issue, we call freeeze on our so called constants.
# bad
class Car
WHEELS = 4
COLORS = [
'red',
'blue',
'yellow'
]
end
# good
class Car
WHEELS = 4.freeze
COLORS = [
'red',
'blue',
'yellow'
].freeze
end