A guide for programming in style.
Set up your laptop with this script and these dotfiles.
Get the code.
git clone git@github.com:organization/project.git
Set up the project's dependencies.
cd project
bundle --binstubs
rake db:create
rake db:schema:load
rake db:seed
Add Heroku remotes for staging and production environments.
git remote add staging git@heroku.com:<app>-staging.git
git remote add production git@heroku.com:<app>-production.git
Use Heroku config to get ENV
variables.
heroku config:pull --app <app>-staging
Delete extra lines in .env
, leaving only those needed for app to function
properly.
BRAINTREE_MERCHANT_ID
BRAINTREE_PRIVATE_KEY
BRAINTREE_PUBLIC_KEY
S3_KEY
S3_SECRET
Use Foreman to run the app locally.
foreman start
It uses your .env
file and Procfile
to run processes just like Heroku's
Cedar stack.
Create a local feature branch based off master.
git checkout master
git pull --rebase
git checkout -b feature-xyz
Rebase frequently to incorporate upstream changes.
git fetch origin
git rebase origin/master
<resolve conflicts>
When feature is complete and tests pass, commit the changes.
rake
git add -A
git status
git commit -v
Write a good commit message.
Present-tense summary under 50 characters
* More information about commit (under 72 characters).
* More information about commit (under 72 characters).
Share your branch.
git push origin [branch]
Submit a Github pull request.
Ask for a code review in Campfire.
A team member other than the author reviews the pull request.
They make comments and ask questions directly on lines of code in the Github web interface or in Campfire.
For changes which they can make themselves, they check out the branch.
git checkout <branch>
rake db:migrate
rake
git diff staging..HEAD
They make small changes right in the branch, test the feature in browser, run tests, commit, and push.
When satisfied, they comment on the pull request Ready to squash and merge.
If there are multiple commits in the branch, squash them.
git rebase -i staging/master
rake
View a list of new commits. View changed files. Merge branch into staging.
git checkout staging
git fetch staging
git reset --hard staging/master
git log staging..[branch]
git diff --stat [branch]
git merge [branch] --ff-only
Deploy to Heroku.
git push staging
Run migrations (if necessary).
heroku run rake db:migrate --app <app>
Restart the dynos if migrations were run.
heroku restart --app <app>
Introspect to make sure everything's ok.
watch heroku ps --app <app>
Test the feature in browser.
Delete your remote feature branch.
git push origin :[branch]
Delete your local feature branch.
git branch -d [branch]
Close pull request and comment Merged.
Deploy to production.
git checkout production
git fetch production
git reset --hard production/master
git log production..staging
git diff --stat staging/master
git merge staging --ff-only
git push production
heroku run rake db:migrate --app <app>
heroku restart --app <app>
watch heroku ps --app <app>
Watch logs and metrics dashboards. If the feature is working, merge into master.
git checkout master
git fetch origin
git log production..master
git merge production --ff-only
git push origin master
- Delete trailing whitespace.
- Don't include spaces after
(
,[
or before]
,)
. - Don't vertically align tokens on consecutive lines.
- Include spaces around infix method invocations like
+
and-
. - Indent continued lines two spaces.
- Indent private methods equal to public methods.
- Limit lines to a maximum of 80 characters.
- Order methods and attributes alphabetically where possible.
- Use 2 space indentation (no tabs) unless otherwise noted.
- Use an empty line between methods, blocks and conditionals.
- Use spaces around operators, after commas, colons and semicolons, around
{
and before}
.
- Avoid abbreviations.
- Avoid Hungarian notiation (
szName
). - Avoid types in names (
user_array
). - Name background jobs with a
Job
suffix. - Name the enumeration parameter the singular of the collection.
- Name variables, methods, and classes to reveal intent.
- Treat acronyms as words in names (
XmlHttpRequest
notXMLHTTPRequest
), even if the acronym is the entire name (class Html
notclass HTML
).
- Aggressively remove duplication during development.
- Avoid comments.
- Avoid global variables.
- Avoid long parameter lists.
- Be consistent.
- Don't duplicate the functionality of a built-in library.
- Don't swallow exceptions or "fail silently."
- Don't write code that guesses at future functionality.
- Exceptions should be exceptional.
- Keep the code simple.
- Limit the number of collaborators of an object.
- Prefer classes to modules when designing functionality that is shared by multiple objects.
- Prefer composition over inheritance.
- Prefer small methods. One line is best.
- Prefer small objects with a single, well-defined responsibility.
- Tell, don't ask.
- Define functions that operate on
window
or DOM in scope ofwindow
. - Initialize arrays using
[]
. - Initialize empty objects and hashes using
{}
. - Use
CamelCase
for prototypes,mixedCase
for variables and functions,SCREAMING_SNAKE_CASE
for constants,_single_leading_underscore
for private variables and functions. - Use
data-
attributes to bind event handlers. - Use the module pattern to control method visibility.
- Avoid conditional modifiers (lines that end with conditionals).
- Avoid hashes as optional parameters. Does the method do too much?
- Avoid including code and gems in source control that are specific to your
development machine or process. Examples:
.rvmrc
,.swp
- Avoid meta-programming.
- Avoid monkey-patching core classes.
- Avoid ternary operators (
boolean ? true : false
). Use multi-lineif
instead to emphasize code branches. - Define the project's Ruby version in the Gemfile.
- Prefer
detect
, notfind
, andselect
, notfind_all
, to avoid confusion with ActiveRecord and keepselect
/reject
symmetry. - Prefer
map
, notcollect
, andreduce
, notinject
, due to symmetry and familarity with mapping and reducing in other technologies. - Use
_
for unused block parameters:hash.map { |_, v| v + 1 }
- Use
%{}
for single-line strings needing interpolation and double-quotes. - Use
%w()
, not['', '']
, for an array of words. - Use
&&
and||
for boolean expressions. - Use
||=
freely. - Use
{...}
, notdo..end
, for single-line blocks. - Use
!
suffix for dangerous methods (modifiesself
). - Use
?
suffix for predicate methods (return a boolean). - Use
CamelCase
for classes and modules,snake_case
for variables and methods,SCREAMING_SNAKE_CASE
for constants. - Use
def
with parentheses when there are arguments. - Use
do..end
, not{...}
, for multi-line blocks. - Use
each
, notfor
, for iteration. - Use heredocs for multi-line strings.
- Use
/(?:first|second)/
, not/(first|second)/
, when you don't need the captured group. - Use
private
, notprotected
, to indicate scope. - Use
def self.method
, notdef Class.method
orclass << self
. - Use
Set
, notArray
, for arrays with unique elements. The lookup is faster. - Use single-quotes for strings unless interpolating.
- Avoid the
:except
option in routes. - Avoid
member
andcollection
routes. - Avoid Single Table Inheritance.
- Don't change a migration after it has been committed unless it cannot be solved with another migration.
- Don't invoke a model's class directly from a view.
- Don't use SQL or SQL fragments (
where('inviter_id is not null')
) outside of models. - Keep the
db/schema.rb
under version control. - Limit the number of instance variables shared between controller and view.
- Name initializers for their gem name. Example:
paperclip.rb
- Order controller contents: filters, public methods, private methods.
- Order model contents: constants, attributes, associations, nested attributes, named scopes, validations, callbacks, public methods, private methods.
- Prefer decorators, not view helpers.
- Put all copy text in models, views, controllers, and mailers in
config/locales
. - Set
config.assets.initialize_on_precompile = false
inconfig/application.rb
. - Set default values in the database.
- Use
_path
, not_url
, for named routes everywhere except mailer views. - Use
def self.method
, not thenamed_scope :method
DSL. - Use
I18n.t 'dot.separated.key'
, notI18n.t :key, :scope => [:dot, :separated]
. - Use
has_and_belongs_to_many
if all you need is a join table. Do not include anid
or timestamps. - Use namespaced locale lookup in views by prefixing a period:
t '.title'
. - Use nested routes to express
belongs_to
relationships between resources. - Use SQL, not
ActiveRecord
models, in migrations. - Use the default
render 'partial'
syntax overrender partial: 'partial'
. - Use the
:only
option to explicitly state exposed routes.
- Avoid multicolumn indexes in Postgres. It combines multiple indexes efficiently.
- Create indexes concurrently for tables with existing data in production to avoid table locks and reduced performance during deploys.
- Consider a partial index for queries on booleans.
- Constrain most columns as
NOT NULL
. - Create a read-only Heroku Follower for your production database. If a Heroku database outage occurs, Heroku can use the follower to get your app back up and running faster.
- Index all foreign keys.
- Use a Heroku Follower database for analytics to limit reads on the primary database.
- Define a
PRIORITY
constant at the top of the class. - Define two public methods:
self.enqueue
andperform
. - Enqueue the job in
self.enqueue
like this. - Put background jobs in
app/jobs
. - Store IDs, not
ActiveRecord
objects for cleaner serialization, then re-find theActiveRecord
object in theperform
method. - Subclass the job from
Struct.new(:something_id)
. - Use
Delayed::Job
for background jobs.
- Set
config.action_mailer.raise_delivery_errors = true
in the development environment. - Set
config.action_mailer.delivery_method = :test
in the test environment. - Use one
ActionMailer
for the app. Name itMailer
. - Use SendGrid or Amazon SES to deliver email in staging and production environments.
- Use single recipient SMTP in staging environment.
- Use the user's name in the
From
header and email in theReply-To
when delivering email on behalf of the app's users.
- Use AssetSync to serve assets from S3.
- Use Bourbon for Sass mixins.
- Use Bourne for stubs and spies.
- Use Braintree for credit card processing.
- Use Clearance for authentication.
- Use Factory Girl to set up test data.
- Use Geocoder for geocoding.
- Use Haml for view templates.
- Use Money for money objects.
- Use New Relic for performance monitoring.
- Use Paperclip for file uploads.
- Use Thin for serving web requests.
- Use WebMock to disable real HTTP requests.
- Avoid
its
,let
,let!
,specify
,subject
, and other DSLs. Prefer explicitness and consistency. - Disable real HTTP requests to external services with
WebMock.disable_net_connect!
. - Don't prefix
it
blocks with 'should'. - Name outer
describe
blocks after the method under test. Use.method
for class methods and#method
for instance methods. - Order factories.rb: sequences, traits, factory definitions.
- Order factory definitions alphabetically by factory name.
- Order factory attributes: implicit attributes, newline, explicit attributes, child factory definitions. Each section's attributes are alphabetical.
- Run specs with
--format documentation
. - Test background jobs with a matcher.
- Use a
context
block for each execution path through the method. - Use a Fake to stub requests to external services.
- Use a
before
block to define phases of Four Phase Test. - Use integration tests to execute the entire app.
- Use non-SUT methods in expectations when possible.
- Use one expectation per
it
block. - Use stubs and spies (not mocks) in isolated tests.
- Don't support clients without Javascript.
- Don't support IE6.