API 문서화 가이드라인

이 가이드는 Ruby on Rails API 문서화 가이드라인을 다룹니다.

이 가이드를 읽고 나면 다음을 알 수 있습니다:

  • 문서화 목적으로 효과적인 문장을 작성하는 방법.
  • 다양한 종류의 Ruby 코드를 문서화하기 위한 스타일 가이드라인.

RDoc

Rails API 문서RDoc으로 생성됩니다. 이를 생성하려면 rails 루트 디렉토리에 있는지 확인하고 bundle install을 실행한 후 다음을 실행하세요:

$ bundle exec rake rdoc

생성된 HTML 파일은 ./doc/rdoc 디렉토리에서 찾을 수 있습니다.

참고: RDoc Markup Reference를 참조하여 구문에 대한 도움을 받으세요.

링크

Rails API 문서는 GitHub에서 보기 위한 것이 아니므로 RDoc 링크 마크업을 사용하여 현재 API에 상대적인 링크를 사용해야 합니다.

이는 GitHub Markdown과 api.rubyonrails.orgedgeapi.rubyonrails.org에 게시되는 생성된 RDoc 간의 차이 때문입니다.

예를 들어 [link:classes/ActiveRecord/Base.html]를 사용하여 RDoc에 의해 생성된 ActiveRecord::Base 클래스에 대한 링크를 만듭니다.

이는 [https://api.rubyonrails.org/classes/ActiveRecord/Base.html]와 같은 절대 URL을 사용하는 것보다 선호됩니다. 이렇게 하면 현재 문서 버전(예: edgeapi.rubyonrails.org) 외부로 이동하게 됩니다.

용어

간단하고 선언적인 문장을 작성하세요. 간결함이 장점입니다. 핵심 내용에 집중하세요.

# 나쁨
# 캐싱으로 인해 코드 변경 결과를 볼 수 없을 수 있습니다.

# 좋음
# 캐싱은 코드 변경 결과 확인을 방해합니다.

현재 시제를 사용하세요:

# 나쁨
# 해시를 반환했습니다.
# 해시를 반환할 것입니다.
# 해시를 반환합니다.

# 좋음
# 해시를 반환합니다.

주석을 대문자로 시작하고 일반적인 구두점 규칙을 따르세요:

# 나쁨
# 내부적으로 명명된 인스턴스 변수로 백업된 속성 리더를 선언합니다.

# 좋음
# 내부적으로 명명된 인스턴스 변수로 백업된 속성 리더를 선언합니다.

현재 방식으로 읽는 사람에게 명시적으로 그리고 암시적으로 전달하세요. edge에서 권장되는 관용구를 사용하세요. 필요한 경우 선호되는 접근 방식을 강조하기 위해 섹션을 재정렬하세요. 문서는 모범 사례와 공식적인 최신 Rails 사용법의 모델이어야 합니다.

# 나쁨
# Book.where('name = ?', "Where the Wild Things Are")
# Book.where('year_published < ?', 50.years.ago)

# 좋음
# Book.where(name: "Where the Wild Things Are")
# Book.where(year_published: ...50.years.ago)

문서는 간단하면서도 포괄적이어야 합니다. 경계 사례를 탐색하고 문서화하세요. 모듈이 익명인 경우 어떻게 됩니까? 컬렉션이 비어 있는 경우 어떻게 됩니까? 인수가 nil인 경우 어떻게 됩니까?

명명

Rails 구성 요소의 올바른 이름에는 단어 사이에 공백이 있습니다. 예를 들어 “Active Support”. ActiveRecord는 Ruby 모듈이지만 Active Record는 ORM입니다. Rails 문서는 일관되게 Rails 구성 요소의 올바른 이름을 참조해야 합니다.

# 좋음
# Active Record 클래스는 ActiveRecord::Base를 상속하여 생성할 수 있습니다.

“Rails 애플리케이션"을 참조할 때는 "엔진” 또는 “플러그인"이 아닌 "애플리케이션"을 사용하세요. Rails 앱은 서비스 지향 아키텍처에 대해 논의하는 경우가 아니라면 "서비스"가 아닙니다.

# 나쁨
# 프로덕션 서비스는 상위로 상태를 보고할 수 있습니다.
# Devise는 Rails 인증 애플리케이션입니다.

# 좋음
# 프로덕션 애플리케이션은 상위로 상태를 보고할 수 있습니다.
# Devise는 Rails 인증 엔진입니다.

소프트웨어 이름을 올바르게 철자하세요. 확실하지 않은 경우 공식 문서와 같은 권위 있는 소스를 참조하세요.

# 좋음
# Arel
# ERB
# Hotwire
# HTML
# JavaScript
# minitest
# MySQL
# npm
# PostgreSQL
# RSpec

"SQL"에 대해 "an"을 사용하세요:

# 나쁨
# SQL 문을 생성합니다.
# SQLite 데이터베이스를 시작합니다.

# 좋음
# SQL 문을 생성합니다.
# SQLite 데이터베이스를 시작합니다.

대명사

"당신"과 "당신의"를 피하는 표현을 선호하세요.

# 나쁨
# 콜백에서 +return+ 문을 사용해야 하는 경우 명시적으로 정의하는 것이 좋습니다.

# 좋음
# +return+이 필요한 경우 메서드를 명시적으로 정의하는 것이 좋습니다.

그렇지만 "세션 쿠키가 있는 사용자"와 같은 가상의 사람을 참조할 때는 성 중립적 대명사(they/their/them)를 사용해야 합니다.

  • he 또는 she 대신 they를 사용합니다.
  • him 또는 her 대신 them을 사용합니다.
  • his 또는 her 대신 their를 사용합니다.
  • his 또는 hers 대신 theirs를 사용합니다.
  • himself 또는 herself 대신 themselves를 사용합니다.

미국 영어

미국 영어(color, center, modularize 등)를 사용하세요. 미국 영어와 영국 영어 철자 차이 목록을 참조하세요.

옥스퍼드 쉼표

옥스퍼드 쉼표("red, white, and blue"가 아닌 "red, white, and blue”)를 사용하세요.

예제 코드

기본 사항과 흥미로운 포인트 또는 함정을 보여주는 의미 있는 예를 선택하세요.

올바른 렌더링을 위해 왼쪽 여백에서 두 칸 들여쓰기 하세요. 예제 자체는 Rails 코딩 규약을 따라야 합니다.

짧은 문서에는 “Examples” 레이블을 명시적으로 사용하지 않고 단락 뒤에 바로 나옵니다:

# 요소 컬렉션을 모두 +to_s+하고 연결하여 형식화된 문자열로 변환합니다.
#
#   Blog.all.to_fs # => "First PostSecond PostThird Post"

반면에 구조화된 큰 문서에는 별도의 “Examples” 섹션이 있을 수 있습니다:

# ==== Examples
#
#   Person.exists?(5)
#   Person.exists?('5')
#   Person.exists?(name: "David")
#   Person.exists?(['name LIKE ?', "%#{query}%"])

표현식의 결과는 “# => "로 소개되어 수직으로 정렬됩니다:

# 정수가 짝수인지 홀수인지 확인하는 경우.
#
#   1.even? # => false
#   1.odd?  # => true
#   2.even? # => true
#   2.odd?  # => false

줄이 너무 길면 주석을 다음 줄에 배치할 수 있습니다:

#   label(:article, :title)
#   # => <label for="article_title">Title</label>
#
#   label(:article, :title, "A short title")
#   # => <label for="article_title">A short title</label>
#
#   label(:article, :title, "A short title", class: "title_label")
#   # => <label for="article_title" class="title_label">A short title</label>

puts 또는 p와 같은 출력 메서드를 사용하지 마세요.

반면에 일반 주석에는 화살표를 사용하지 않습니다:

#   polymorphic_url(record)  # same as comment_url(record)

SQL

SQL 문을 문서화할 때는 출력 앞에 =>를 사용하지 마세요.

예를 들어,

#   User.where(name: 'Oscar').to_sql
#   # SELECT "users".* FROM "users"  WHERE "users"."name" = 'Oscar'

IRB

IRB, Ruby의 대화형 REPL에 대한 동작을 문서화할 때는 항상 명령 앞에 irb>를 붙이세요. 출력은 =>로 시작해야 합니다.

예를 들어,

# 기본 키(id) 10인 고객을 찾습니다.
#   irb> customer = Customer.find(10)
#   # => #<Customer id: 10, first_name: "Ryan">

Bash / 명령줄

명령줄 예제의 경우 항상 명령 앞에 $를 붙이세요. 출력에는 접두사를 붙일 필요가 없습니다.

# 다음 명령을 실행하세요:
#   $ bin/rails new zomg
#   ...

부울

술어와 플래그의 경우 정확한 값보다는 부울 의미를 문서화하는 것이 좋습니다.

Ruby에서 정의된 "true” 또는 “false"를 사용할 때는 일반 글꼴을 사용합니다. 싱글톤 truefalse는 고정 폭 글꼴을 사용해야 합니다. "truthy"와 같은 용어는 피하세요. Ruby는 언어에서 true와 false를 정의하므로 이 단어들은 기술적 의미를 가지며 대체할 필요가 없습니다.

일반적인 규칙으로, 절대적으로 필요한 경우가 아니라면 싱글톤을 문서화하지 마세요. 이렇게 하면 !! 또는 삼항 연산자와 같은 인위적인 구조가 방지되고 리팩토링이 가능하며, 구현에서 호출되는 메서드의 정확한 반환 값에 코드가 의존할 필요가 없습니다.

예를 들어:

# +config.action_mailer.perform_deliveries+는 메일이 실제로 전송될지 여부를 지정하며 기본적으로 true입니다.

사용자는 플래그의 실제 기본값을 알 필요가 없으므로 부울 의미만 문서화합니다.

술어의 예:

# 컬렉션이 비어 있으면 true를계속해서 한국어 번역을 제공하겠습니다.

부울
--------

술어와 플래그의 경우 정확한 값보다는 부울 의미를 문서화하는 것이 좋습니다.

Ruby에서 정의된 "true" 또는 "false" 사용할 때는 일반 글꼴을 사용합니다. 싱글톤 `true` `false` 고정  글꼴을 사용해야 합니다. "truthy" 같은 용어는 피하세요. Ruby 언어에서 true false 정의하므로  단어들은 기술적 의미를 가지며 대체할 필요가 없습니다.

일반적인 규칙으로, 절대적으로 필요한 경우가 아니라면 싱글톤을 문서화하지 마세요. 이렇게 하면 `!!` 또는 삼항 연산자와 같은 인위적인 구조가 방지되고 리팩토링이 가능하며, 구현에서 호출되는 메서드의 정확한 반환 값에 코드가 의존할 필요가 없습니다.

예를 들어:

```ruby
# +config.action_mailer.perform_deliveries+는 메일이 실제로 전송될지 여부를 지정하며 기본적으로 true입니다.

사용자는 플래그의 실제 기본값을 알 필요가 없으므로 부울 의미만 문서화합니다.

술어의 예:

# 컬렉션이 비어 있으면 true를 반환합니다.
#
# 컬렉션이 로드된 경우 +collection.size.zero?+와 동일합니다. 컬렉션이 로드되지 않은 경우 +!collection.exists?+와 동일합니다. 이미 로드되지 않은 컬렉션이고 레코드를 가져올 것이라면 +collection.length.zero?+를 확인하는 것이 좋습니다.
def empty?
  if loaded?
    size.zero?
  else
    @target.blank? && !scope.exists?
  end
end

API는 특정 값에 전념하지 않고 술어 의미를 가지므로 충분합니다.

파일 이름

일반적인 규칙으로 애플리케이션 루트에 상대적인 파일 이름을 사용하세요: config/routes.rbroutes.rb 또는 RAILS_ROOT/config/routes.rb보다 좋습니다.

글꼴

고정 폭 글꼴

다음의 경우 고정 폭 글꼴을 사용하세요:

  • 상수, 특히 클래스 및 모듈 이름
  • 메서드 이름
  • nil, false, true, self와 같은 리터럴
  • 기호
  • 메서드 매개변수
  • 파일 이름
  • HTML 태그 및 속성
  • CSS 선택기, 속성 및 값
class Array
  # +to_param+을 모든 요소에 호출하고 결과를 슬래시로 연결합니다.
  # 이는 Action Pack의 +url_for+에 의해 사용됩니다.
  def to_param
    collect { |e| e.to_param }.join '/'
  end
end

경고: +...+를 사용한 고정 폭 글꼴은 일반 클래스, 모듈, 메서드 이름, 기호, 경로(슬래시 포함) 등과 같은 단순한 내용에만 작동합니다. 그 외의 경우 <tt>...</tt>를 사용하세요.

다음 명령으로 RDoc 출력을 빠르게 테스트할 수 있습니다:

$ echo "+:to_param+" | rdoc --pipe
# => <p><code>:to_param</code></p>

예를 들어 공백이나 따옴표가 있는 코드는 <tt>...</tt> 형식을 사용해야 합니다.

일반 글꼴

"true” 및 “false"가 Ruby 키워드가 아닌 영어 단어인 경우 일반 글꼴을 사용합니다:

# 지정된 컨텍스트 내에서 모든 유효성 검사를 실행합니다.
# 오류가 없으면 true를, 그렇지 않으면 false를 반환합니다.
#
# 인수가 false(기본값은 +nil+)이면 +new_record?+가 true이면 컨텍스트가
# <tt>:create</tt>로, 그렇지 않으면 <tt>:update</tt>로 설정됩니다.
#
# +:on+ 옵션이 없는 유효성 검사는 컨텍스트에 관계없이 실행됩니다.
# 일부 +:on+ 옵션이 있는 유효성 검사는 지정된 컨텍스트에서만 실행됩니다.
def valid?(context = nil)
  # ...
end

설명 목록

옵션, 매개변수 등의 목록에서는 항목과 설명 사이에 하이픈을 사용하세요(콜론을 사용하는 것보다 읽기 좋습니다. 일반적으로 옵션은 기호):

# * <tt>:allow_nil</tt> - 속성이 +nil+이면 유효성 검사를 건너뜁니다.

설명은 대문자로 시작하고 마침표로 끝납니다. 표준 영어입니다.

추가 세부 정보와 예제를 제공하려는 경우 옵션 섹션 스타일을 사용할 수 있습니다.

ActiveSupport::MessageEncryptor#encrypt_and_sign은 이 방법의 좋은 예입니다.

# ==== Options
#
# [+:expires_at+]
#   메시지가 만료되는 날짜와 시간입니다. 이 날짜 및 시간 이후에는 메시지 확인이 실패합니다.
#
#     message = encryptor.encrypt_and_sign("hello", expires_at: Time.now.tomorrow)
#     encryptor.decrypt_and_verify(message) # => "hello"
#     # 24시간 후...
#     encryptor.decrypt_and_verify(message) # => nil

동적으로 생성된 메서드

(module|class)_eval(STRING)로 생성된 메서드에는 생성된 코드의 인스턴스가 있는 주석이 있습니다. 이 주석은 템플릿에서 2 칸 떨어져 있습니다:

(module|class)_eval(STRING) 코드 주석

결과 줄이 200열 이상으로 너무 넓은 경우 주석을 호출 위에 배치하세요:

# def self.find_by_login_and_activated(*args)
#   options = args.extract_options!
#   ...
# end
self.class_eval %{
  def self.#{method_id}(*args)
    options = args.extract_options!
    ...
  end
}, __FILE__, __LINE__

메서드 가시성

Rails 문서를 작성할 때는 사용자 API와 내부 API를 구분하는 것이 중요합니다.

Ruby의 private 범위에 있는 메서드는 사용자 API에서 제외됩니다. 그러나 일부 내부 API 메서드는 프레임워크의 다른 부분에서 호출될 수 있도록 Ruby의 public 범위에 있어야 합니다. 이러한 메서드를 사용자 API에서 제외하려면 RDoc의 :nodoc: 지시문을 사용하세요.

ActiveRecord::Core::ClassMethods#arel_table의 예:

module ActiveRecord::Core::ClassMethods
  def arel_table # :nodoc:
    # 마법을 수행합니다..
  end
end

이 메서드는 public이지만 사용자가 신뢰할 수 없습니다. 이 메서드의 이름이나 반환 값이 변경되거나 완전히 제거될 수 있습니다. :nodoc:으로 표시하면 사용자 API 문서에서 제외됩니다.

기여자로서 API가 사용자 API인지 내부 API인지 고려하는 것이 중요합니다. Rails 팀은 전체 사용 중단 주기를 거치지 않고는 사용자 API에 대한 변경 사항을 만들지 않겠다는 약속을 했습니다. 따라서 이미 private이 아닌 경우 내부 메서드 또는 모듈에 :nodoc:을 추가해야 합니다. (모듈 또는 클래스에 :nodoc:을 추가하면 모든 메서드가 내부 API이며 사용자 API 문서에서 제거되어야 합니다.)

Rails 스택 관련

Rails API의 일부를 문서화할 때는 전체 Rails 스택을 염두에 두는 것이 중요합니다. 문서화 중인 메서드 또는 클래스의 동작은 컨텍스트에 따라 달라질 수 있습니다.

그러한 예가 ActionView::Helpers::AssetTagHelper#image_tag입니다:

# image_tag("icon.png")
#   # => <img src="/assets/icon.png" />

독립적으로 image_tag//assets/docs/rails/guides/icon.png를 반환할 것입니다. 그러나 Asset Pipeline을 포함한 전체 Rails 스택을 고려하면 위와 같은 결과를 볼 수 있습니다.

우리는 프레임워크의 동작을 문서화하고자 합니다. 단일 메서드가 아닌 전체 기본 Rails 스택을 사용할 때의 동작입니다.

Rails 팀이 특정 API를 처리하는 방법에 대해 질문이 있는 경우 이슈 트래커에 티켓을 열거나 패치를 보내는 것을 주저하지 마세요.