DHH의 Rails 코딩 스타일
바닐라 Rails로 충분하다 — 37시그널스의 철학
DHH(David Heinemeier Hansson)는 Rails 창시자이자 37시그널스(Basecamp, HEY)의 CTO입니다. 수십 년간 프로덕션 Rails 코드를 작성하며 정립한 코딩 스타일은 "단순함"과 "프레임워크 신뢰"에 기반합니다.
1. 바닐라 Rails로 충분하다
습관적으로 설치하는 외부 라이브러리(Devise, Redis, Sidekiq 등)를 최소화하고, 프레임워크에 내장된 기본 기능을 최대한 활용하라는 원칙입니다.
실제로 37시그널스는 외부 의존성을 줄이고 데이터베이스만으로 백그라운드 작업과 캐시 등을 처리하여 배포와 운영을 단순화합니다.
# ❌ 습관적으로 추가하는 외부 gem
gem 'devise' # → has_secure_password로 충분한 경우가 많음
gem 'sidekiq' # → Rails 8의 Solid Queue로 대체 가능
gem 'redis' # → Solid Cache, Solid Cable로 DB 기반 대체
gem 'pundit' # → 간단한 before_action 콜백으로 충분할 수 있음
# ✅ Rails 내장 기능 먼저 검토
has_secure_password # 인증
ActiveJob + Solid Queue # 백그라운드 작업
Rails.cache + Solid Cache # 캐싱
Action Cable + Solid Cable # WebSocket
핵심: gem을 추가하기 전에 "Rails 내장 기능으로 해결할 수 없는가?"를 먼저 자문하세요.
2. 모든 것을 CRUD로 매핑하라
커스텀 액션을 만드는 대신, 새로운 리소스를 만들어 표준 CRUD(Create/Read/Update/Delete)에 매핑합니다.
# ❌ 커스텀 액션 — 컨트롤러가 비대해짐
resources :cards do
member do
patch :close # CardsController#close
patch :reopen # CardsController#reopen
patch :archive # CardsController#archive
end
end
# ✅ 새 리소스로 CRUD 매핑 — 일관된 패턴
resources :cards do
resource :closure, only: [:create, :destroy] # create=닫기, destroy=다시 열기
resource :archival, only: [:create, :destroy] # create=보관, destroy=복원
end
이렇게 하면:
ClosuresController#create= 카드 닫기ClosuresController#destroy= 카드 다시 열기모든 컨트롤러가
index/show/new/create/edit/update/destroy7개 액션만 사용라우팅이 RESTful하고 예측 가능
3. 상태를 불리언(Boolean)이 아닌 레코드로 관리하라
특정 상태를 true/false 컬럼으로 추가하는 대신, 별도의 레코드를 생성하여 관리합니다.
# ❌ 불리언 컬럼 — 히스토리 없음
class Card < ApplicationRecord
# closed: boolean (컬럼)
# 언제 닫혔는지? 누가 닫았는지? 알 수 없음
end
# ✅ 레코드로 관리 — 자연스러운 히스토리
class Closure < ApplicationRecord
belongs_to :card
belongs_to :user # 누가 닫았는지
# created_at # 언제 닫았는지 (자동)
end
class Card < ApplicationRecord
has_many :closures
def closed?
closures.exists?
end
def closed_by
closures.last&.user
end
end
장점:
언제, 누가 닫았는지 자연스럽게 기록
닫기/열기 이력 전체 조회 가능
상태 변경에 대한 감사(audit) 로그 자동 생성
destroy로 상태 취소 가능 (불리언 토글보다 명확)
학습 방법
37시그널스의 오픈소스 코드를 GitHub에서 직접 살펴보세요:
Campfire — 37시그널스의 채팅 앱 (Rails 기본 기능만으로 구현)
ONCE — 한 번 사서 영원히 쓰는 앱 (외부 의존성 최소화 철학)
Basecamp — DHH의 핵심 프로덕트
실천 과제: 다음 프로젝트에서 습관적으로 쓰던 외부 라이브러리 하나를 빼고 직접 구현해 보세요. has_secure_password로 Devise 없이 인증을 만들어 보거나, Solid Queue로 Sidekiq을 대체해 보는 것에서 시작합니다.
핵심 포인트
새 기능 추가 전 → "Rails 내장으로 할 수 있나?" 먼저 확인
커스텀 액션이 필요할 때 → 새 리소스(Controller)로 분리하여 CRUD 매핑
상태 변경 기능 → 불리언 컬럼 대신 별도 모델(레코드) 생성
Gemfile에 gem 추가 전 → Rails 8 Solid 시리즈(Queue/Cache/Cable) 검토
37시그널스 오픈소스(Campfire, ONCE) 코드를 읽으며 패턴 학습
다음 프로젝트에서 외부 gem 하나를 빼고 직접 구현해보기
장점
- ✓ 배포·운영이 단순해짐 (Redis, 별도 워커 불필요)
- ✓ 의존성 줄어 보안 취약점 감소
- ✓ 컨트롤러가 일관된 7개 액션 패턴 유지
- ✓ 상태 변경 히스토리가 자동으로 남음
- ✓ RESTful 라우팅으로 API 예측 가능
- ✓ Rails 업그레이드 시 깨지는 부분 최소화
단점
- ✗ 초기에는 직접 구현하는 게 느릴 수 있음 (학습 비용)
- ✗ 리소스 분리가 과하면 컨트롤러 파일 수 증가
- ✗ 팀원이 관습적 Rails(Devise 등)에 익숙하면 혼란 가능
- ✗ 대규모 서비스에서는 Redis/Sidekiq이 성능상 필요할 수 있음