Rubocop 적용기 & 백엔드 개발 주관적 꿀팁

2018-09-19 / 발표자 : 채민균

EmptyLinesAroundClassBody:
  Enabled: false
EmptyLinesAroundMethodBody:
  Enabled: false
Metrics/LineLength:
  Enabled: false
SpaceInsideBlockBraces:
  Enabled: false
TrailingBlankLines:
  Enabled: false
SpaceInsideHashLiteralBraces:
  Enabled: false
EmptyLinesAroundBlockBody:
  Enabled: false
ClassAndModuleChildren:
  Enabled: false
NumericLiterals:
  Enabled: false
BlockLength:
  Enabled: false
MethodLength:
  Enabled: false
Documentation:
  Enabled: false
AbcSize:
  Enabled: false
SymbolArray:
  Enabled: false
EmptyLineAfterMagicComment:
  Enabled: false
IndentHash:
  Enabled: false
ClassLength:
  Enabled: false
PerceivedComplexity:
  Enabled: false
CyclomaticComplexity:
  Enabled: false
IndentationWidth:
  Enabled: false
AsciiComments:
  Enabled: false
Metrics/ParameterLists:
  Enabled: false
ExpandPathArguments:
  Enabled: false
MultilineOperationIndentation:
  Enabled: false
MultilineMethodCallIndentation:
  Enabled: false
EmptyMethod:
  Enabled: false
Security/Open:
  Enabled: false
Style/InverseMethods:
  Enabled: false
Layout/CommentIndentation:
  Enabled: false


AllCops:
  Excludes:
  - db/schema.rb

Adison Performance Rubocop Setting

Style:
  Enabled: false
Layout:
  Enabled: false
Metrics/LineLength:
  Enabled: false
Metrics/BlockLength:
  Enabled: false
Metrics/MethodLength:
  Enabled: false
Metrics/AbcSize:
  Enabled: false
Metrics/ClassLength:
  Enabled: false
Metrics/ModuleLength:
  Enabled: false

AllCops:
  Excludes:
  - db/schema.rb

Recommend Rubocop Setting

Notice that you have to change file name to pre-commit

1. $ cd .git/hooks
2. $ mv pre-commit.sample pre-commit
3. add this text to pre-commit file and save


#!/bin/sh
#
# Check for ruby style errors

red='\033[0;31m'
green='\033[0;32m'
yellow='\033[0;33m'
NC='\033[0m'

if git rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	# Change it to match your initial commit sha
	against=123acdac4c698f24f2352cf34c3b12e246b48af1
fi

# Check if rubocop is installed for the current project
bin/bundle exec rubocop -v >/dev/null 2>&1 || { echo >&2 "${red}[Ruby Style][Fatal]: Add rubocop to your Gemfile"; exit 1; }

# Get only the staged files
FILES="$(git diff --cached --name-only --diff-filter=AMC | grep "\.rb$" | tr '\n' ' ')"

echo "${green}[Ruby Style][Info]: Checking Ruby Style${NC}"

if [ -n "$FILES" ]
then
	echo "${green}[Ruby Style][Info]: ${FILES}${NC}"

	if [ ! -f '.rubocop.yml' ]; then
	  echo "${yellow}[Ruby Style][Warning]: No .rubocop.yml config file.${NC}"
	fi

	# Run rubocop on the staged files
	bin/bundle exec rubocop ${FILES}

	if [ $? -ne 0 ]; then
	  echo "${red}[Ruby Style][Error]: Fix the issues and commit again${NC}"
	  exit 1
	fi
else
	echo "${green}[Ruby Style][Info]: No files to check${NC}"
fi

exit 0

How to Set Rubocop Git Pre-Commit Hook

#1 before    

    if event_type.include?(INSTALL)
      type = INSTALL
    elsif event_type.include?(OPEN)
      type = OPEN
    elsif event_type.include?(PREREGISTRATION)
      type = PREREGISTRATION
    else
      type = EVENT
    end

Applied Rubocop Examples

#1 after

type = if event_type.include?(INSTALL)
         INSTALL
       elsif event_type.include?(OPEN)
         OPEN
       elsif event_type.include?(PREREGISTRATION)
         PREREGISTRATION
       else
         EVENT
       end

Applied Rubocop Examples

#2 before

    def delete_whitespace(foo)
        foo.gsub(' ', '')
    end

Applied Rubocop Examples

#2 after

    def delete_whitespace(foo)
        foo.delete(' ')
    end

Applied Rubocop Examples

#2 performance test

def go
  s = Time.now.to_f
  10000.times do
    qwe = '405 402 401 350 392 4178 3841 473 1274y1 17405 120412 421830'
    qwe.gsub!(' ', '')
  end
  f = Time.now.to_f
  f - s
end

def to
  s = Time.now.to_f
  10000.times do
    qwe = '405 402 401 350 392 4178 3841 473 1274y1 17405 120412 421830'
    qwe.delete!(' ')
  end
  f = Time.now.to_f
  f - s
end

a = 0
b = 0

100.times do
    a += go
    b += to
end

# a = 2.8520665168762207
# b = 0.8430917263031006
# It's almost 3.4 times fast!!!

Applied Rubocop Examples

#3 before

    if string_value == 'a' || 
        string_value == 'b' || 
        string_value == 'c' || 
        string_value == 'd'
        
        # do something
    end

Applied Rubocop Examples

#4 after
        
    if %w[a b c d].include?(string_value)
        # do something
    end

Applied Rubocop Examples

#4 performance test
        
def go
  s = Time.now.to_f
  array = %w[a w e f k o d a x d f q w e r t y u u z x d 1 3 5 6 d c b d s a s 2 4 6 2 3 4 6 7 7 1 z v d q]
  count = 0
  array.each {|element| count += 1 if element == 'a' || element == 'x' || element == 'd'}
  f = Time.now.to_f
  f - s
end

def to
  s = Time.now.to_f
  array = %w[a w e f k o d a x d f q w e r t y u u z x d 1 3 5 6 d c b d s a s 2 4 6 2 3 4 6 7 7 1 z v d q]
  count = 0
  candidates = %w[a x d]
  array.each {|element| count += 1 if candidates.include?(element)}
  f = Time.now.to_f
  f - s
end

a = 0
b = 0

100000.times do
  a += go
  b += to
end

#a = 1.6121020317077637
#b = 1.032500982284546
#It's almost 1.6 times fast!!!

Applied Rubocop Examples

#5 Do not use these function prefix with this case
        
1.get_ with no parameter

def get_element
end

def element
end

2.set_ with one parameter

def set_element(foo)
end

def element=(foo)
end

3.is_ has_

def is_unique
end

def unique?
end


Applied Rubocop Examples

#5 Do not use case

link : http://midwire.github.io/blog/2011/08/26/ruby-performance-case-vs-if-elsif/

Applied Rubocop Examples

고찰에서 나온 주관적

  • legacy 가 생기는 걸까?
  • 왜 예상치 못한 bug 가 발생하는 걸까?

How to Reduce Legacy

1. 안쓰는 기능이 생기면 관련코드는 적어도 주석처리하거나 삭제할 것.

2. 초반 설계를 잘할 것.(어렵...ㅠ)

How to Reduce Bug

1. 컨트롤러는 최대한 가벼울 것. (요약문 짜듯이!)

컨트롤러가 무거우면 반드시 스파게티 코드가 생기기마련

rubocop 설정만 해주면 Metrics cop 이 알아서 잡아줄 것이다.

2. Active Record에는 해당 테이블에'만' 종속적인 함수'만' 짠다!

A.rb 에서 다른 모델을 불러오는 코드가 있다면 다른 모델이나 다른 계층으로 불리할 것.

여러 모델에서 같이 사용하는 함수가 있다면 이 또한 다른 모델이나 다른 계층으로 불리할 것.

3. 함수는 그 자체로 온전할 것.

모든 파라미터 값들에 대해 예외처리를 해줘야 나중에 해당 함수를 사용하는 다른 사람들로 부터 버그를 피할 수 있다. 특히 nil case.

4. 특정 케이스가 아니라면 여러 서버의 코드에 싱크를 맞춰놓을 것.

apply rubocop

By mingyun chae

apply rubocop

루비온레일즈에서 rubocop 을 적용했던 내용을 공유합니다.

  • 506