Skip to content

Instantly share code, notes, and snippets.

@ecoologic
Last active August 11, 2020 09:47
Show Gist options
  • Save ecoologic/5537908 to your computer and use it in GitHub Desktop.
Save ecoologic/5537908 to your computer and use it in GitHub Desktop.
My Conventions
{}.as_json # {}
{}.to_json # "{}"
# query / command
user_params # query, no get_params etc, prefer queries over commands, leads to more declarative code, which is simpler
remote_document # Query, not get_document, more declarative
buy_document! # Exception to the above, it's probably a POST and I want to express that it's not a free call
prepare_document! # Bang to express imperative behaviour (?)
compact_params(params) # command - takes args and can be reused
compacted_user_params # YES, a noun is better
compact_user_params # NO!! no need for a command, try to use a _query_ first
# Order
User.ordered # (adj) values: 'asc' 'desc' etc
user.position # 1,2,3 etc., not order, which is the "type"
# When it's two words in the dictionary, it should be two words in your code (eg: first_name) - Easier to remember
# File System naming should be consistent with Namespacing. eg: `/app/gateways/payment.rb` -> `Gateways::Payment` - Easier to remember
logo_file_name = logo_file_base_name = "logo.png" # As returned by File.basename
logo_file_root_name = 'logo'
logo_partial_path = logo_path = "public/logo.png"
logo_full_path = "/app/public/logo.path"
# Use the name of the abstraction - More modular, easier to change
Gateways::Payment # Instead of Gateways::Paypal
PaymentGateway # In Rails, to keep conventions
Paypal::Gateway # Other way around, because paypal is the wrapper module
# Call because it's a "doer" class (so does one thing only) - easier polymorphism
user = UserBuilder.new(attributes).call
# user not as a keyword arg because the name makes it obvious
presenter = UserPresenter.new(user)
# Use keyword arguments when the param is not in the name of the class
user = Users::Services::Creator.new(user, params[:user], { skip_children: true }).call
def a_private_method(dont, use, keyword, arguments) # because it's shorter and it's local
end
# Pass primitives, never AR models, test using spec_helper, not rails_helper
PaymentGateway.new(credit_card_info: credit_card_params, amount_in_cents: 50).pay!
# info/data usually hashes
validate :valid_field # prefix valid_ for validations
before_save :sync_xx_fields # sync is excellent for callbacks
before_create :set_xx_fields # set OK here
class UserService
# Params are mandatory
def initialize(user, params, options = {})
@user, @params, @options = user, params, options
end
def save
@user.save! # as a default, unless you check if save was successful
# [do stuff]
# return true / false - match AR behavior
end
private
# Private readers, set with `@user = u`, not attr_writers
attr_reader :user, :params, :options
end
def hashify_url(url:) # NOOOO - Redundant
def hashify(url:) # Maybe: Good naming, but beware of SRP
def hashify_url(url) # YES: Separates the logic nicely
def convert_user(user:, options: {}) # NOO: Both these types are implied
def convert_user(user, options = {}) # Nice
def convert_user(user, options) # Defaults are not hints of their type, use them when not passing a value is accepted
end end end end end end
# Always pass the date down to the model (easier to test / debug), SRP
def active_on?(date)
# ... true or false, maybe nil, nothing else
end
# Don't care what is the subject of your comparision,
# Create an expectation that time always increase from left to right
# TODO: starts_on ends_on
before_date < after_date # (always use < when comparing dates, so it's like a temporal line left to right)
before_date < (after_date + offset)
(before_date + offset) < after_date # Never use minus, always plus, simpler to read left to right
date # -> 23/1/16 (for arguments and local vars, not for DB fields)
day # -> cardinal: 1,2,3
purchase.made_on # instead of purchase.date
survey.completed_at # instead of survey.time
# Field name conventions by type:
t.date :due_on # and not due_date
t.datetime :due_at # and not due_time
t.integer :xxx_id # use id only for models
t.string :x_api_uid # use uid for non-AR IDs
VALUES_BY_KEY = { key1: 'value1', key2: 'value2' }
def product_uid; end # product_id is a typical Rails thing, use uid for external services
def product_token; end # _key, _code a bit ambiguous
def x_array; end # NO: avoid Hungarian Notation, give it a name and pluralize it
def xs; end # OK
# A period is a range of time
def active_period
(starts_on..ends_on)
end
def firstname; end # NO: Two words in the dictionary, two words in the code
def first_name; end # OK
def req; end # NO: params / attrs is accepted
def request; end # OK
# Use result for the returning values in procedures
def complex_method
result = []
result = complex_stuff
result
end
# Use the same name for memoization
def things
@things ||= calc_things
end
# Casting
def to_y; end
# Actual call to external service
def get_user; end # same length (:
def set_user; end
def buy_plan; end
def request_user; end # fetch, load
def store_user; end # TODO?? better?
# AVOID
check_xxx # not clear
get_xxx #
# Gemfile: Explain why you're locking a version (in the commit message too)
gem 'my_gem', '1.0.0' # Locked because v 1.0.0 introduced breaking change with xyz
# Rails
def price_incl_tax # NOT price_inc_gst, incl is easier to search and GST could be too specific and regional
end
# Put a link to the PR in the main file of a new feature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment