Backend code styles
In this article we will show you what code style to follow when developing BE.
Rubocop & Easy Style
We want our code to be readable and understandable and since our codebase is large and complex, it's important to follow some basic rules when writing code.
To ensure code style, we use Rubocop with Rails Omakase (rubocop-rails-omakase) and our easy_style gem.
To deal with the styles you, preferably, needs both of them in your Gemfile/gemspec file. Most of our projects already have this installed. Please follow the instruction below.
For platform and plugins put this into Gemfile:
After this run
Dealing with offenses
Every time you see the possibility to fix some offenses - please do it. We keep two ways of exempting specific offenses:
.rubocop_todo.yml- keeps offenses that are fixable and should be fixed eventually.
- to regenerate use
bundle exec rubocop --regenerate-todo .rubocop_ignore.yml- keeps offenses that we want to keep and should be ignored.
- exceptions are added manually, instead of inline disabling
For more info, see https://docs.rubocop.org/rubocop/configuration.html#automatically-generated-configuration
General rules
Do not change Redmine!
Do not change any Redmine files directly unless you have a clear need and approval. As we mentioned in Repository structure Redmine is the main Rails app on which our system is built. Easy8 is a fork of Redmine and upstream updates can overwrite core changes. That means that your code can be lost during updates if it is not coordinated.
Try to use existing code.
Before adding something, inspire yourself within the existing code base. Try to find an applicable existing solution, copy and modify it. On the other hand, avoid blind copy-pasting. When you use a method, you have to know what it does.
Don't be afraid to explore the source code. Look at models, controllers or views and do it similarly - try to follow current syntax or code style. We want our codebase to be consistent.
Comments
Comments are always welcome. Please use YARD docs style.
Comments are required on complex codes. Otherwise you should write a self-labeling code. It means that a method's name describes what it does.
Recommended editor settings
- Two spaces for indentation. Use two spaces for indenting your code and swear an oath to never mix tabs and spaces.
- Unix line-endings. Use UNIX-style newlines (\n), and a newline character as the last character of a file. Windows-style newlines (\r\n) are forbidden inside any repository.
- UTF-8 source coding only
- No whitespaces
- Spaces around curly braces in hashes
- Spaces around curly braces in blocks
- Spaces around arrows
- Do not indent
whencases - Do not indent after
private/protected - Use double quotes
"for strings, we prefer consistency
RubyMine takes care of most of them automatically.
Conventions
ActiveRecord migrations
We are using two types of migrations:
- Schema migrations, located in
db/migrate, handles changes to the database schema. - Data migrations, located in
db/data, which handles only changes of data.
Overwriting templates / partials
One plugin can completely replace a template or a partial of the platform or a plugin which was loaded before it. This pattern can be used to implement changes, but only if you are rewriting more than 50 % of the content.
In case of small additions, create new or use existing hooks. Hooks must be created in the appropriate repository, generally in the platform.
Prefixes
Prefixes are preferred in order to avoid naming conflicts. For plugin Abc for example, use:
-
AbcHelperinstead ofHelper -
label_abc_sum:instead oflabel_sum:in langfiles
Localisation
All text must use I18n and must be translated at least to English. Wording should be clear for developers and follow english translation.
Common prefixes:
button_ error_ field_ label_ text_ title_
Do not overwrite lang keys from Redmine or Easy8.
Indentation and naming
# BAD
issues.map{|x| x.project.versions.map{|y| y.css_classes}}.flatten
# GOOD
issues.flat_map do |issue|
issue.project.versions.map do |version|
version.css_classes
end
end
Class methods
Prefer def self.method_name for class method definitions.
# BAD
class << self
def project_scope(scope, options, _event_type)
scope
end
end
# GOOD
def self.project_scope(scope, options, _event_type)
scope
end
Delegation
When delegating multiple methods to the same target, combine them into a single delegate call.
# BAD
delegate :branches, to: :scm
delegate :tags, to: :scm
# GOOD
delegate :branches, :tags, to: :scm
belong_to relations
Always specify optional:true when defining belongs_to associations which are not required.
HTML & JS
Javascript use ES6 from next/major (ES5 before in case you need some historical bugfix)
For the class attribute use use BEM convention - Block__Element_Modifier / multi-word-block-name__multi-word-element-name_modifier-name_modifier-value:
For the id attribute use _ as separator:
If you haven't found what you're looking for, you can look at community guidelines:
For RUBY try this.
For RAILS try this.