Skip to content

jetthoughts/how-we-work

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

80 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JTology - How We Work

Values & Core Principles

Other Guides:

Base Strucutring Projects

Formatting/Conventions

Base styles guides:

Our updates:

  • Limit lines to 110 characters, in order to remove horizontal scrolling on GitHub when we are doing code review
  • Align parameters like:
# good (normal indent) PREFERABLE
def send_mail(source)
  Mailer.deliver(
    to: 'bob@example.com',
    from: 'us@example.com',
    subject: 'Important message',
    body: source.text
  )
end

# not so bad
def send_mail(source)
  Mailer.deliver(
    to: 'bob@example.com', from: 'us@example.com'
  )
end

# good, but DEPRECATED
def send_mail(source)
  Mailer.deliver(to: 'bob@example.com',
                 from: 'us@example.com',
                 subject: 'Important message',
                 body: source.text)
end
  • Use prefix _ for memo variables:
class TestObject
  attr_reader :attr_name
  
  def attr_name
    @attr_name ||= lazy_calculation_for_attr_name
  end
  
  def public_method_with_memo
    @_public_method_with_memo ||= public_method_with_memo_calculcations
  end
end
  • Stick to Newlines section of Airbnb's Ruby style guide for grouping the code within methods.

Working with Bugs

  • Confirm on the master, the staging and finally on development environment.
  • Add tests with reproduced bugs before add fixes

Ruby on Rails Conventions

  • We use Decorators (in code we called them Carrier) as View and Form objects: introduction how to use them
  • We do not use full Presenters (TODO: add link to first post about them) with any tag generations
  • We do not overuse of Concerns
  • We do not overuse (in 99% of our code we do not see such stuff): send, &., **. To prevent misusage of Ruby Syntax Sugars [link]

Test Conventions

Principles

  • TDD
  • Clarity means that a test should serve as readable documentation for humans, describing the code being tested in terms of its public APIs.
  • A test is complete when its body contains all of the information you need to understand it, and concise when it doesn't contain any other distracting information.

Ref: Testing on the Toilet: What Makes a Good Test?

Rules

  • Tests First[link]
    • Use Black Box testing strategy (there is no other way to support TDD)[link]

      By ignoring the code (Black box testing), it demonstrates a different value system - the tests are valuable alone.

  • We use the meaningful names in the test cases. It makes easier to understand the business logic.[link]
# bad
def test_email_is_normalized
  user = User.create! email: 'Foo@quux.com'
  assert_equal 'foo@quux.com', user.email
end

# good
def test_email_is_normalized
  user = User.create! email: ' thisIsAMixedCaseEmail@example.com'
  assert_equal 'thisisamixedcaseemail@example.com', user.email
end
# BAD
let!(:user_with_big_name) { ... }
let!(:user_with_small_name) { ... }

it 'this test use only user_with_big_name' { expects(response).to have(user_with_big_name) }
it 'this test use only user_with_small_name' { expects(response).to have(user_with_small_name) }
# GOOD
context 'with big name' do
  let(:user) { ... }
  
  it 'this test use only user_with_big_name' { expects(response).to have(user) }
end

context 'with small name' do
  let(:user) { ... }
  
  it 'this test use only user_with_small_name' { expects(response).to have(user) }
end
# BAD
setup do
  big_file_with_all_users = compile_file_from_users(User.all)
end

test 'this test use only user_with_big_name' { assert_includes big_file_with_all_users, 'magic string with all big letter' }
test 'this test use only user_with_small_name' { assert_includes big_file_with_all_users, 'magic string with all small letter' }
# GOOD
test 'this test use only user_with_big_name' do
  result = compile_file_from_users(User.new(name: 'Big Name'))
  assert_includes result, 'Big Name'
end

test 'this test use only user_with_small_name' do
  result = compile_file_from_users(User.new(name: 'Samll Name'))
  assert_includes result, 'Small Name'
end
  • No Dynamic Test generation.[link]
# BAD
{ string: 'zone_id', array: %w[zone_id], hash: { "0" => "zone_id" } }.each do |type, group_by|
  it "returns valid json if group_by is #{type}" do
  end
end
# GOOD
it "returns zone_id json if group_by is string" { }
it "returns [zone_id] json if group_by is array" { }
it "returns { '0' => 'zone_id' } json if group_by is hash" { }
  • Irrelevant Information[link]

    Message for reviewer:

    The test is exposing a lot of irrelevant details about the fixture that distract the test reader from what really affects the behavior of the subject under test.

describe 'PUT Update' do
  let!(:user) { create :user }

  # Bad
  it 'updates user' do
    attributes = { first_name: '..', last_name: '..', role: '..', email: '..' }
    put: :update, params: { attributes }
    expects(response.body).to eq attributes
  end

  # Good
  it 'updates first_name' do
    put: :update, params: { first_name: 'John Dou' }
    expects(response.body).to have_attribute { first_name: 'John Dou' }
  end

  it 'updates email' do
    put: :update, params: { email: 'email@example.com' }
    expects(response.body).to have_attribute { email: 'email@example.com' }
  end

Setup Development Environment

  • bin/setup - cold setup
  • bin/update - update environment on new code updates

Delivery Flow

Our flow is based on GitHub flow with Heroku Review

  • create PR (we convert issues into PR)
  • deploy PR to Heroku (we use Heroku Review to do this automatically)
  • verify on Heroku yourselves
  • ask verify, to code review and to merge (we have Code Review)

TODO/FIXME Notes

  • add issue on GitHub per each note
  • create TODO/FIXME note in the code
  • add in code's note link to GitHub's issue

Git/GitHub

Development Best Practices

Other Tools and Practices to use

Recomended Tutorials

Constraints which makes fun development

Tools:

  • Collaboration:
  • CI:
  • Server Configuation: Ansible
  • Deployments: Capistrano
  • Assets and File Uploads CDN hosting: AWS, CloudFront, Cloudinary (Images Uploads)
  • PAAS for Isolated Staging Testing: Heroku (Ruby on Rails apps), surge.sh (Static HTML)
  • Cache: Memcached/Redis Cloud from Redis Lab
  • JavaScript Base Frameworks: Stimulus, Vanilla JS, Vue.js, React
  • SCM: GitHub