Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Rename repo to "guides", split into 3 guides

* Create "protocol" and "best practices" guides.
* Add belongs_to validation guideline.
* Remove "Always be learning" non sequitur.
* Move Heroku remotes to "protocol."
* Remove `Procfile`. It is in `suspenders`.
* Remove Cedar. It is the current Heroku default. Creating an app using
  `suspenders` per the "protocol" guidelines will do this automatically.
* Move move-out.md to best-practices/README.md.
* Flatten `.env` example code block.
* Improve squashing guideline.
* Separate "Merge" and "Deploy" sections.
  • Loading branch information...
commit 04b6e2ea8597ae46b24247b96da9b04645478fa0 1 parent 67b4e14
@jferris jferris authored croaky committed
View
172 README.md
@@ -1,170 +1,8 @@
-Style Guide
-===========
-
-A guide for programming in style.
-
-High level guidelines:
-
-* Be consistent.
-* Don't rewrite existing code to follow this guide.
-* Don't violate the conventions without a good reason.
-
-A note on the language:
-
-* "Avoid" means don't do it unless you have good reason.
-* "Don't" means there's never a good reason.
-* "Prefer" indicates a better option and its alternative to watch out for.
-* "Use" is a positive instruction.
-
-Heroku
-------
-
-* Have Heroku remotes named "staging" and "production."
-* Use a Procfile to configure your services.
-* Use the [Cedar](https://devcenter.heroku.com/articles/cedar/) stack.
-
-Git
----
-
-* Avoid including files in source control that are specific to your
- development machine or process.
-* Delete local and remote feature branches after merging.
-* Perform work in a feature branch.
-* Prefix feature branch names with your initials.
-* Rebase frequently to incorporate upstream changes.
-* Use a [pull request](http://goo.gl/Kmdee) for code reviews.
-* Write a [good commit message](http://goo.gl/w11us).
-
-Formatting
-----------
-
-* Avoid inline comments.
-* Break long lines after 80 characters.
-* Delete trailing whitespace.
-* Don't include spaces after `(`, `[` or before `]`, `)`.
-* Don't vertically align tokens on consecutive lines.
-* If you break up an argument list, keep the parenthesis on its own line.
-* If you break up a hash, keep the curly braces on their own lines.
-* Indent continued lines two spaces.
-* Indent private methods equal to public methods.
-* Use 2 space indentation (no tabs).
-* Use an empty line between methods.
-* Use spaces around operators, after commas, after colons and semicolons, around
- `{` and before `}`.
-
-Naming
+Guides
------
-* Avoid abbreviations.
-* Avoid types in names (`user_array`).
-* Name the enumeration parameter the singular of the collection.
-* Name variables, methods, and classes to reveal intent.
-* Treat acronyms as words in names (`XmlHttpRequest` not `XMLHTTPRequest`),
- even if the acronym is the entire name (`class Html` not `class HTML`).
-
-JavaScript
-----------
-
-* Use CoffeeScript.
-
-CoffeeScript
-------------
-
-* Initialize arrays using `[]`.
-* Initialize empty objects and hashes using `{}`.
-* Use `CamelCase` for classes, `mixedCase` for variables and functions,
- `SCREAMING_SNAKE_CASE` for constants, `_single_leading_underscore` for
- private variables and functions.
-
-Ruby
-----
-
-[Sample](https://github.com/thoughtbot/style-guide/blob/master/ruby-sample.rb)
-
-* Avoid conditional modifiers (lines that end with conditionals).
-* Avoid ternary operators (`boolean ? true : false`). Use multi-line `if`
- instead to emphasize code branches.
-* Define the project's [Ruby version in the
- Gemfile](http://gembundler.com/man/gemfile.5.html#RUBY-ruby-).
-* Prefer `detect` over `find`.
-* Prefer `inject` over `reduce`.
-* Prefer `map` over `collect`.
-* Prefer `select` over `find_all`.
-* Prefer single quotes for strings.
-* Use `_` for unused block parameters.
-* Use `%{}` for single-line strings needing interpolation and double-quotes.
-* Use `&&` and `||` for Boolean expressions.
-* Use `{...}` for single-line blocks. Use `do..end` for multi-line blocks.
-* Use `?` suffix for predicate methods.
-* Use `CamelCase` for classes and modules, `snake_case` for variables and
- methods, `SCREAMING_SNAKE_CASE` for constants.
-* Use `def self.method`, not `def Class.method` or `class << self`.
-* Use `def` with parentheses when there are arguments.
-* Use `each`, not `for`, for iteration.
-* Use heredocs for multi-line strings.
-
-ERB
----
-
-* When wrapping long lines, keep the method name on the same line as the ERB
- interpolation operator and keep each method argument on its own line.
-
-[Sample](https://github.com/thoughtbot/style-guide/blob/master/erb-sample.erb)
-
-Rails
------
-
-* Avoid `member` and `collection` routes.
-* Avoid the `:except` option in routes.
-* Don't reference a model class directly from a view.
-* Don't use protected controller methods.
-* Don't use SQL or SQL fragments (`where('inviter_id is not null')`) outside
- of models.
-* Keep the `db/schema.rb` under version control.
-* If there are default values, set them in migrations.
-* Name initializers for their gem name.
-* Order controller contents: filters, public methods, private methods.
-* Order model contents: constants, macros, public methods, private methods.
-* Put application-wide partials in the
- [`app/views/application`](http://goo.gl/5Z8Vv) directory.
-* Use `_path`, not `_url`, for named routes everywhere except mailer views.
-* Use `def self.method`, not the `scope :method` DSL.
-* Use SQL, not `ActiveRecord` models, in migrations.
-* Use the default `render 'partial'` syntax over `render partial: 'partial'`.
-* Use the `:only` option to explicitly state exposed routes.
-
-Background Jobs
----------------
-
-* Define a `PRIORITY` constant at the top of delayed job classes.
-* Define two public methods: `self.enqueue` and `perform`.
-* Put delayed job classes in `app/jobs`.
-
-Email
------
-
-* Use one `ActionMailer` for the app. Name it `Mailer`.
-* Use the user's name in the `From` header and email in the `Reply-To` when
- [delivering email on behalf of the app's users](http://goo.gl/5w1ck).
-
-Testing
--------
-
-[Sample](https://github.com/thoughtbot/style-guide/blob/master/rspec-sample.rb)
-
-* Avoid `its`, `let`, `let!`, `specify`, `before`, and `subject`.
-* Avoid using instance variables in tests.
-* Don't prefix `it` block descriptions 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 attributes: implicit attributes, explicit attributes,
- child factory definitions. Each section's attributes are alphabetical.
-* Order factory definitions alphabetically by factory name.
-* Prefer `eq` to `==` in RSpec.
-* Separate setup, exercise, verification, and teardown phases with newlines.
-* Use an `it` example for each execution path through the method.
-* Use one factories.rb file per project.
-* Use [stubs and spies](http://goo.gl/EciDJ) (not mocks) in isolated tests.
+Guides for getting things done, programming well, and programming in style.
-[Always be learning](http://learn.thoughtbot.com).
+* [Protocol](/thoughtbot/guides/blob/master/protocol)
+* [Best Practices](/thoughtbot/guides/blob/master/best-practices)
+* [Style](/thoughtbot/guides/blob/master/style)
View
78 best-practices/README.md
@@ -0,0 +1,78 @@
+Best Practices
+==============
+
+A guide for programming well.
+
+General
+-------
+
+* 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](http://rdd.me/yichhgvu).
+* [Keep the code simple](http://rdd.me/ko2aqda2).
+
+Object-Oriented Design
+----------------------
+
+* Avoid global variables.
+* Avoid long parameter lists.
+* Limit the number of collaborators of an object.
+* Prefer composition over inheritance.
+* Prefer small methods. One line is best.
+* Prefer small objects with a single, well-defined responsibility.
+* [Tell, don't ask](http://goo.gl/Ztawt).
+
+Ruby
+----
+
+* Avoid optional parameters. Does the method do too much?
+* Avoid monkey-patching core classes.
+* Prefer classes to modules when designing functionality that is shared by
+ multiple models.
+* Prefer `private` when indicating scope. Use `protected' only with comparison
+ methods like `def ==(other)`, `def <(other)`, and `def >(other)`.
+
+Rails
+-----
+
+* Don't change a migration after it has been merged into master if the desired
+ change can be solved with another migration.
+* Validate the associated `belongs_to` object (`user`), not the database
+ column (`user_id`).
+
+Postgres
+--------
+
+* Avoid multicolumn indexes in Postgres. It [combines multiple
+ indexes](http://goo.gl/pY3Po) efficiently.
+* Consider a [partial index](http://goo.gl/YC8Jt) for queries on booleans.
+* Constrain most columns as [`NOT NULL`](http://goo.gl/0GeBr).
+
+Background Jobs
+---------------
+
+* Store IDs, not `ActiveRecord` objects for cleaner serialization, then re-find
+ the `ActiveRecord` object in the `perform` method.
+
+Email
+-----
+
+* Use [SendGrid](http://goo.gl/Kxu9W) or [Amazon SES](http://goo.gl/A5jAA) to
+ deliver email in staging and production environments.
+
+Testing
+-------
+
+* Disable real HTTP requests to external services with
+ `WebMock.disable_net_connect!`.
+* Test background jobs with a [`Delayed::Job` matcher](http://goo.gl/bzBlN).
+* Use a [Fake](http://goo.gl/YR7Hh) to stub requests to external services.
+* Use integration tests to execute the entire app.
+* Use non-[SUT](http://goo.gl/r5Ti2) methods in expectations when possible.
+
+Browsers
+--------
+
+* Don't support clients without Javascript.
+* Don't support IE6.
View
175 protocol/README.md
@@ -0,0 +1,175 @@
+Protocol
+========
+
+A guide for getting things done.
+
+Set up laptop
+-------------
+
+Set up your laptop with [this script](/thoughtbot/laptop)
+and [these dotfiles](/thoughtbot/dotfiles).
+
+Create Rails app
+----------------
+
+Get Suspenders.
+
+ gem install suspenders
+
+Create the app.
+
+ suspenders app --heroku true --github organization/app
+
+Set up Rails app
+----------------
+
+Get the code.
+
+ git clone git@github.com:organization/app.git
+
+Set up the app's dependencies.
+
+ cd project
+ bundle --binstubs
+ rake db:setup
+
+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](/ddollar/heroku-config) to get `ENV`
+variables.
+
+ heroku config:pull -r staging
+
+Delete extra lines in `.env`, leaving only those needed for app to function
+properly. For example: `BRAINTREE_MERCHANT_ID` and `S3_SECRET`.
+
+Use [Foreman](http://goo.gl/oy4uw) to run the app locally.
+
+ foreman start
+
+It uses your `.env` file and `Procfile` to run processes just like Heroku's
+[Cedar](https://devcenter.heroku.com/articles/cedar/) stack.
+
+Write a feature
+---------------
+
+Create a local feature branch based off master.
+
+ git checkout master
+ git pull --rebase
+ git checkout -b your-initials-new-feature
+
+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](http://goo.gl/w11us).
+
+ 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](http://goo.gl/Kmdee).
+
+Ask for a code review in [Campfire](http://campfirenow.com).
+
+Review code
+-----------
+
+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/master..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 merge.`
+
+Merge
+-----
+
+Rebase interactively. Squash commits like "Fix whitespace" into one or a
+small number of valuable commit(s). Edit commit messages to reveal intent.
+
+ git rebase -i origin/master
+ rake
+
+View a list of new commits. View changed files. Merge branch into master.
+
+ git log origin/master..[branch]
+ git diff --stat origin/master
+ git checkout master
+ git merge [branch] --ff-only
+ git push
+
+Delete your remote feature branch.
+
+ git push origin :[branch]
+
+Delete your local feature branch.
+
+ git branch -d [branch]
+
+Deploy
+------
+
+View a list of new commits. View changed files. Deploy to
+[Heroku](https://devcenter.heroku.com/articles/quickstart) staging.
+
+ git fetch staging
+ git log staging/master..master
+ git diff --stat staging/master
+ git push staging
+
+Run migrations (if necessary).
+
+ heroku run rake db:migrate -r staging
+
+Restart the dynos if migrations were run.
+
+ heroku restart -r staging
+
+[Introspect](http://goo.gl/tTgVF) to make sure everything's ok.
+
+ watch heroku ps -r staging
+
+Test the feature in browser.
+
+Deploy to production.
+
+ git fetch production
+ git log production/master..master
+ git diff --stat production/master
+ git push production
+ heroku run rake db:migrate -r production
+ heroku restart -r production
+ watch heroku ps -r production
+
+Watch logs and metrics dashboards.
+
+Close pull request and comment `Merged.`
View
161 style/README.md
@@ -0,0 +1,161 @@
+Style
+=====
+
+A guide for programming in style.
+
+High level guidelines:
+
+* Be consistent.
+* Don't rewrite existing code to follow this guide.
+* Don't violate the conventions without a good reason.
+
+A note on the language:
+
+* "Avoid" means don't do it unless you have good reason.
+* "Don't" means there's never a good reason.
+* "Prefer" indicates a better option and its alternative to watch out for.
+* "Use" is a positive instruction.
+
+Git
+---
+
+* Avoid including files in source control that are specific to your
+ development machine or process.
+* Delete local and remote feature branches after merging.
+* Perform work in a feature branch.
+* Prefix feature branch names with your initials.
+* Rebase frequently to incorporate upstream changes.
+* Use a [pull request](http://goo.gl/Kmdee) for code reviews.
+* Write a [good commit message](http://goo.gl/w11us).
+
+Formatting
+----------
+
+* Avoid inline comments.
+* Break long lines after 80 characters.
+* Delete trailing whitespace.
+* Don't include spaces after `(`, `[` or before `]`, `)`.
+* Don't vertically align tokens on consecutive lines.
+* If you break up an argument list, keep the parenthesis on its own line.
+* If you break up a hash, keep the curly braces on their own lines.
+* Indent continued lines two spaces.
+* Indent private methods equal to public methods.
+* Use 2 space indentation (no tabs).
+* Use an empty line between methods.
+* Use spaces around operators, after commas, after colons and semicolons, around
+ `{` and before `}`.
+
+Naming
+------
+
+* Avoid abbreviations.
+* Avoid types in names (`user_array`).
+* Name the enumeration parameter the singular of the collection.
+* Name variables, methods, and classes to reveal intent.
+* Treat acronyms as words in names (`XmlHttpRequest` not `XMLHTTPRequest`),
+ even if the acronym is the entire name (`class Html` not `class HTML`).
+
+JavaScript
+----------
+
+* Use CoffeeScript.
+
+CoffeeScript
+------------
+
+* Initialize arrays using `[]`.
+* Initialize empty objects and hashes using `{}`.
+* Use `CamelCase` for classes, `mixedCase` for variables and functions,
+ `SCREAMING_SNAKE_CASE` for constants, `_single_leading_underscore` for
+ private variables and functions.
+
+Ruby
+----
+
+[Sample](/thoughtbot/guides/blob/master/style/samples/ruby.rb)
+
+* Avoid conditional modifiers (lines that end with conditionals).
+* Avoid ternary operators (`boolean ? true : false`). Use multi-line `if`
+ instead to emphasize code branches.
+* Define the project's [Ruby version in the
+ Gemfile](http://gembundler.com/man/gemfile.5.html#RUBY-ruby-).
+* Prefer `detect` over `find`.
+* Prefer `inject` over `reduce`.
+* Prefer `map` over `collect`.
+* Prefer `select` over `find_all`.
+* Prefer single quotes for strings.
+* Use `_` for unused block parameters.
+* Use `%{}` for single-line strings needing interpolation and double-quotes.
+* Use `&&` and `||` for Boolean expressions.
+* Use `{...}` for single-line blocks. Use `do..end` for multi-line blocks.
+* Use `?` suffix for predicate methods.
+* Use `CamelCase` for classes and modules, `snake_case` for variables and
+ methods, `SCREAMING_SNAKE_CASE` for constants.
+* Use `def self.method`, not `def Class.method` or `class << self`.
+* Use `def` with parentheses when there are arguments.
+* Use `each`, not `for`, for iteration.
+* Use heredocs for multi-line strings.
+
+ERb
+---
+
+[Sample](/thoughtbot/guides/blob/master/style/samples/erb.rb)
+
+* When wrapping long lines, keep the method name on the same line as the ERb.
+ interpolation operator and keep each method argument on its own line.
+
+Rails
+-----
+
+* Avoid `member` and `collection` routes.
+* Avoid the `:except` option in routes.
+* Don't reference a model class directly from a view.
+* Don't use protected controller methods.
+* Don't use SQL or SQL fragments (`where('inviter_id is not null')`) outside
+ of models.
+* Keep the `db/schema.rb` under version control.
+* If there are default values, set them in migrations.
+* Name initializers for their gem name.
+* Order controller contents: filters, public methods, private methods.
+* Order model contents: constants, macros, public methods, private methods.
+* Put application-wide partials in the
+ [`app/views/application`](http://goo.gl/5Z8Vv) directory.
+* Use `_path`, not `_url`, for named routes everywhere except mailer views.
+* Use `def self.method`, not the `scope :method` DSL.

Could you please clarify the benefit of self.method versus scope :method?

got it, thank you for clarification!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+* Use SQL, not `ActiveRecord` models, in migrations.
+* Use the default `render 'partial'` syntax over `render partial: 'partial'`.
+* Use the `:only` option to explicitly state exposed routes.
+
+Background Jobs
+---------------
+
+* Define a `PRIORITY` constant at the top of delayed job classes.
+* Define two public methods: `self.enqueue` and `perform`.
+* Put delayed job classes in `app/jobs`.
+
+Email
+-----
+
+* Use one `ActionMailer` for the app. Name it `Mailer`.
+* Use the user's name in the `From` header and email in the `Reply-To` when
+ [delivering email on behalf of the app's users](http://goo.gl/5w1ck).
+
+Testing
+-------
+
+[Sample](/thoughtbot/guides/blob/master/style/samples/testing.rb)
+
+* Avoid `its`, `let`, `let!`, `specify`, `before`, and `subject`.

Please, explain why should I avoid let and subject?

@jferris Admin
jferris added a note

We have a blog post coming out before too long that will hopefully explain.

thanks :)

@jferris Looking forward to the blog post. I referenced this comment on my answer to What is the argument against using before, let and subject in RSpec tests?

+1 For the blog post, I'm really interested to hear y'all's thoughts :-)

Is there any update on this? :) I'd love to see what you guys have to say

@drapergeek Admin

The blog post went up a while back. Check it out here: http://robots.thoughtbot.com/post/34709581001/lets-not

@georgebrock Admin

@darthdeus This is probably the blog post @jferris was referring to: http://robots.thoughtbot.com/post/34709581001/lets-not

thanks guys :smile_cat:

@jferris Admin
jferris added a note

That was indeed the blog post I was referring to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+* Avoid using instance variables in tests.
+* Don't prefix `it` block descriptions 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 attributes: implicit attributes, explicit attributes,
+ child factory definitions. Each section's attributes are alphabetical.
+* Order factory definitions alphabetically by factory name.
+* Prefer `eq` to `==` in RSpec.
+* Separate setup, exercise, verification, and teardown phases with newlines.
+* Use an `it` example for each execution path through the method.
+* Use one factories.rb file per project.
+* Use [stubs and spies](http://goo.gl/EciDJ) (not mocks) in isolated tests.
View
0  erb-sample.erb → style/samples/erb.rb
File renamed without changes
View
0  ruby-sample.rb → style/samples/ruby.rb
File renamed without changes
View
0  rspec-sample.rb → style/samples/testing.rb
File renamed without changes
@divineforest

Please, explain why should I avoid let and subject?

@jferris

We have a blog post coming out before too long that will hopefully explain.

@prakashmurthy

@jferris Looking forward to the blog post. I referenced this comment on my answer to What is the argument against using before, let and subject in RSpec tests?

@topherfangio

+1 For the blog post, I'm really interested to hear y'all's thoughts :-)

@darthdeus

Is there any update on this? :) I'd love to see what you guys have to say

@drapergeek

The blog post went up a while back. Check it out here: http://robots.thoughtbot.com/post/34709581001/lets-not

@darthdeus

thanks guys :smile_cat:

@jferris

That was indeed the blog post I was referring to.

@alienatix

Could you please clarify the benefit of self.method versus scope :method?

@alienatix

got it, thank you for clarification!

Please sign in to comment.
Something went wrong with that request. Please try again.