[R] R Style Guide by Hadley Wickham - 2. Syntax (2)

해당 포스트는 Hadley Wickham이 작성한 'The tidyverse style guide' 를 번역하여 정리한 글입니다.


Lists
Intro - 0. Welcome
Analysis - 1. Files
Analysis - 2. Syntax (1)
Analysis - 2. Syntax (2)
Analysis - 3. Functions
Analysis - 4. Pipes
Analysis - 5. ggplot2
Packages - 6. Files
Packages - 7. Documentation
Packages - 8. Tests
Packages - 9. Error messages
Packages - 10. News
Packages - 11. Git/GitHub


2. 문법(Syntax)

2.3 함수 호출(Function calls)

2.3.1 명명된 인수(Named arguments)

함수 인수(function's arguments)는 일반적으로 두 가지 범주로 구분됩니다. 하나는 계산할 데이터를 제공하고, 다른 하나는 계산에 사용되는 세부 사항들을 조정합니다. 함수를 호출할 때, 데이터 인수(data arguments)의 이름은 매우 일반적으로 사용되기 때문에 보통은 생략하고 사용합니다. 만약 인수(arguments)의 기본값을 재정의 해야한다면 인수의 전체 이름을 사용하시면 됩니다.

아래 예제 mean()의 인수는 ?mean 또는 help(mean) 를 통해 확인할 수 있으며, 데이터 인수(data argument) x는 일반적으로 인수 이름을 생략하고 사용합니다.

Default S3 method : mean(x, trim = 0, na.rm = FALSE, ...)

# Good
mean(1:10, na.rm = TRUE)

# Bad
mean(x = 1:10, , FALSE) # 중간 인수값 누락
mean(, TRUE, x = c(1:10, NA)) # 첫번째 인수값 누락

2.3.2 할당(Assignment)

함수 호출시에는 할당(assignment)을 사용하지 않는 것이 좋습니다.

# Good
x <- complicated_function()
if (nzchar(x) < 1) {
  # do something
}

# Bad
if (nzchar(x <- complicated_function()) < 1) {
  # do something
} 

유일하게 오작동(side-effect)을 확인하는 기능은 예외입니다.
output <- capture.output(x <- f())

2.4 제어 흐름(Control flow)

2.4.1 코드 블록(Code Blocks)

중괄호({})는 R코드의 가장 중요한 계층 구조를 정의하며, 계층(hierarchy)의 구조의 규칙은 아래와 같습니다.

  • {(opening brace)는 줄(line)의 마지막 글자가 되어야 하며, 관련 코드(ex: if절, 함수 선언, 후행 쉼표 등)는 {와 동일한 라인에 있어야 합니다.
  • 코드의 내용(contents)은 두 칸 들여(indent)써야 합니다.
  • }는 줄(line)의 첫 번째 글자가 되어야 합니다.

들여쓰기(indent)
들여쓰기(indent)는 일반적으로 2칸 또는 4칸을 사용합니다. tidyverse에서는 들여쓰기(indent)를 2칸으로 가이드 하고 있습니다.

# Good
if (y < 0 && debug) {
  message("y is negative")
}

if (y == 0) {
  if (x > 0) {
    log(x)
  } else {
    message("x is negative or zero")
  }
} else {
  y^x
}

test_that("call1 returns an ordered factor", {
  expect_s3_class(call1(x, y), c("factor", "ordered"))
})

tryCatch(
  {
    x <- scan()
    cat("Total: ", sum(x), "\n", sep = "")
  },
  interrupt = function(e) {
    message("Aborted by user")
  }
)

# Bad
if (y < 0 && debug) {
message("Y is negative")
} # 코드 내용(contents) 들여쓰기 미적용 

if (y == 0)
{
    if (x > 0) {
      log(x)
    } else {
  message("x is negative or zero")
    }
} else { y ^ x } # 들여쓰기(indent) 오사용

2.4.2 인라인 상태문(Inline Statements)

오작동(side-effect)이 없다면 한 줄로 작성 가능한 간단한 코드에 대해서는 중괄호({})를 사용하지 않아도 됩니다.

# Good
y <- 10
x <- if (y < 20) "Too low" else "Too high"

return(), stop(), continue과 같이 제어 흐름에 영향을 미치는 함수를 사용할 때에는, 해당 중괄호({}) 블록안에서 사용해야 합니다.

# Good
if (y < 0) {
  stop("Y is negative")
}

find_abs <- function(x) {
  if (x > 0) {
    return(x)
  }
  x * -1
}

# Bad
if (y < 0) stop("Y is negative") # 중괄호 미사용

if (y < 0)
  stop("Y is negative") # 중괄호 미사용

find_abs <- function(x) {
  if (x > 0) return(x)
  x * -1
} # 중괄호 미사용

2.4.3 암시적 강제 형변환(Implicit type coercion)

if 명령문의 조건식에는 암시적 유형 강제를 피하는 것이 좋습니다.
예) numeric(숫자) → logical(논리)

# Good
if (length(x) > 0) {
  # do something
}

# Bad
if (length(x)) {
  # do something
} # length(x)는 판단할 수 있는 조건(논리형)이 아님

2.4.4 스위치 상태문(Switch Statements)

Switch 문?
조건문과 반복문 같이 흐름을 제어하는 문법으로, 주로 if문을 많이 사용합니다. 좀 더 자세한 사용법은 아래 링크에서 확인할 수 있습니다.

https://cran.r-project.org/doc/manuals/r-release/R-lang.html#switch

  • switch() 원소 값을 위치(position) 기반으로 사용하는 것은 좋지 않습니다. [Bad #1]
  • 각 원소(elements)는 동일한 라인에 위치해야 합니다.
  • 원소(element)들은 = 뒤에 공백을 가지고 있어야 합니다.
  • 입력에 대한 사전 유효성 검증이 되지 않은 경우, 오류를 제공해야 합니다. [Good #2]
# Good
switch(x
  a = ,
  b = 1, 
  c = 2,
  stop("Unknown `x`", call. = FALSE) #2
)

# Bad
switch(y, 1, 2, 3) #1
switch(x, a = , b = 1, c = 2)
switch(x, a =, b = 1, c = 2)

2.5 긴 줄(Long lines)

코드는 한 줄에 80 자로 제한하는 것이 좋습니다.

이는 코드의 가독성을 위함이며 80자로 제한할 경우 적당한 크기의 글꼴로 출력된 페이지에 편안하게 맞춰집니다. 만약 페이지에 공간이 부족하다면, 이것은 일부 코드를 별도의 기능으로 캡슐화(encapsulate) 해야 한다는 좋은 징조를 나타냅니다.

함수 호출(function call)이 너무 길어서 한 줄에 들어가지 않는 경우, '함수 이름(function name)', '각 인수(each argument)', '닫는 괄호()' 는 각각 한줄씩 사용하는 것이 좋습니다. 이것은 추후 코드를 더 쉽게 읽고 변경할 수 있도록 만들어줍니다.

# Good
do_something_very_complicated(
  something = "that",
  requires = many,
  arguments = "some of which may be long"
)

# Bad
do_something_very_complicated("that", requires, many, arguments,
                              "some of which may be long"
                              )

'2.3.1 명명된 인수(Named arguments)'에서 설명한 바와 같이,

매우 일반적인 인수에 대해서는 인수 이름을 생략할 수 있습니다.

아래와 같이, 전체 함수 호출이 여러 줄에 걸쳐 있어도 인수 이름이 없는 짧은 인수는 함수 이름과 같은 줄에 있을 수 있습니다.

map(x, f,
  extra_argument_a = 10,
  extra_argument_b = c(1, 43, 390, 210209)
)

문자열 함수 paste() 또는 stop() 함수와 같이 인수들(arguments)간 서로 밀접한 관계가 있는 경우 여러 개의 인수를 같은 줄에 배치할 수 있습니다.

문자열을 작성할 때에는 가능하다면 코드 한 줄을 출력(output) 한 줄로 일치시키는 것이 좋습니다.

# Good
paste0(
  "Requirement: ", requires, "\n",
  "Result: ", result, "\n"
)

# Bad
paste0(
  "Requirement: ", requires,
  "\n", "Result: ",
  result, "\n")

2.6 세미콜론(Semicolons)

세미콜론(;)을 한 라인의 끝에 사용하거나, 한 라인에 여러 개의 명령을 적용하는데 세미콜론(;)을 사용하지 않는게 좋습니다.

세미콜론(Semicolons, ;)
일반적으로 세미콜론(Semicolons)은 실행 가능한 단위 함수 또는 명령문을 구분할 때 사용합니다.
기능적으로 하나의 라인에 여러 단위 명령문을 실행시키는 것은 가능하나 tidyverse에서 권장하는 문법은 아닙니다.

2.7 할당(Assignment)

할당(Assignment)에는 = 가 아닌 <-를 사용하는 것이 좋습니다.

# Good
x <- 5

# Bad
x = 5

2.8 데이터(Data)

2.8.1 문자 벡터(Character vectors)

텍스트(text) 인용이 필요할 경우, 기본적으로 작은 따옴표(')가 아닌 큰 따옴표(")를 사용하는 것이 좋습니다.[Good #1]

단, 텍스트에 이미 큰 따옴표(")가 있고 작은 따옴표(')가 없는 경우에는 작은 따옴표(')로 사용하는 것이 가능합니다.[Good #2, #3]

# Good
"Text" #1
'Text with "quotes"' #2
'<a href="http://style.tidyverse.org">A link</a>' #3

# Bad
'Text'
'Text with "double" and \'single\' quotes'

2.8.2 논리 벡터(Logical vectors)

논리 벡터(Logical vectors)를 사용할 때에는, 약어(T 또는 F)가 아닌 전체 문구(TRUE 또는 FALSE)를 사용하는 것이 좋습니다.

2.9 주석(Comments)

주석(Comment)의 각 라인은 주석 기호(#)와 띄어쓰기 한 칸 공백으로 시작해야 합니다.

데이터 분석 코드에서 중요한 결과 및 분석적 결정을 기록하는데 사용하며, 만약

코드의 기능을 설명하기 위해 주석이 필요한 경우라면 코드를 더 깔끔(clearer)하게 재작성

하는 것이 좋습니다.

또한 코드에 설명이 많은 경우라면, R Markdown을 사용하는 것도 좋은 방법입니다.

출처

[1] The tidyverse style guide
[2] Syntax: Operator Syntax and Precedence
[3] Advanced R by Hadley Wickham
[4] R Markdown from R Studio

the-tidyverse-style-guide-by-Hadley-Wickham.pdf
165.9 kB

▲ The tidyverse style gudie 원문 다운받기