NEGABARO Rails

Rails ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ํ•ต์‹ฌ ๊ฐœ๋…๋“ค์„ ์ •๋ฆฌํ•œ ๋ฐฑ๊ณผ์‚ฌ์ „์ž…๋‹ˆ๋‹ค.

๐Ÿงฑ Foundation

๐Ÿ—๏ธ

MVC ํŒจํ„ด

Model-View-Controller โ€” Rails์˜ ํ•ต์‹ฌ ์•„ํ‚คํ…์ฒ˜

Model(๋ฐ์ดํ„ฐ/๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง), View(ํ™”๋ฉด ํ‘œ์‹œ), Controller(์š”์ฒญ ์ฒ˜๋ฆฌ/์ค‘๊ฐœ)๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ถ„๋ฆฌํ•˜๋Š” ์„ค๊ณ„ ํŒจํ„ด. Rails์˜ ๋ชจ๋“  ๊ฒƒ์€ MVC๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“

Convention over Configuration

Rails์˜ ํ•ต์‹ฌ ์ฒ ํ•™ โ€” ๊ทœ์•ฝ์ด ์„ค์ •๋ณด๋‹ค ์šฐ์„ 

๋ช…์‹œ์ ์ธ ์„ค์ • ํŒŒ์ผ ๋Œ€์‹  ์ด๋ฆ„ ๊ทœ์•ฝ(naming convention)์„ ๋”ฐ๋ฅด๋ฉด, Rails๊ฐ€ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ฒ ํ•™. ์˜ˆ: Post ๋ชจ๋ธ โ†’ posts ํ…Œ์ด๋ธ” โ†’ PostsController โ†’ app/views/posts/

๐Ÿ“

Rails ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

ํ”„๋กœ์ ํŠธ ํด๋”๋ณ„ ์—ญํ• ๊ณผ ์ปจ๋ฒค์…˜

Rails ํ”„๋กœ์ ํŠธ์˜ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋Š” MVC ํŒจํ„ด์„ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. app/, config/, db/, test/ ๋“ฑ ๊ฐ ํด๋”์˜ ์—ญํ• ์ด ๋ช…ํ™•ํžˆ ์ •ํ•ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿง…

Rack & Middleware

Rails ์•„๋ž˜์—์„œ ๋™์ž‘ํ•˜๋Š” HTTP ์ฒ˜๋ฆฌ ๋ ˆ์ด์–ด

Rack์€ Ruby ์›น ์„œ๋ฒ„์™€ ํ”„๋ ˆ์ž„์›Œํฌ ์‚ฌ์ด์˜ ์ธํ„ฐํŽ˜์ด์Šค ๊ทœ์•ฝ์ž…๋‹ˆ๋‹ค. Middleware๋Š” ์š”์ฒญ/์‘๋‹ต์„ ๊ฐ€๋กœ์ฑ„์–ด ์ฒ˜๋ฆฌํ•˜๋Š” ์ค‘๊ฐ„ ๋ ˆ์ด์–ด๋กœ, ์–‘ํŒŒ๊ป์งˆ์ฒ˜๋Ÿผ ๊ฒน๊ฒน์ด ์Œ“์ž…๋‹ˆ๋‹ค.

๐Ÿšฆ Routing & Controllers

๐Ÿ—บ๏ธ

RESTful Routes

resources ํ•œ ์ค„๋กœ 7๊ฐœ ๋ผ์šฐํŠธ ์ž๋™ ์ƒ์„ฑ

REST(Representational State Transfer) ์›์น™์— ๋”ฐ๋ผ ๋ฆฌ์†Œ์Šค ๋‹จ์œ„๋กœ URL์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค. resources :posts ํ•œ ์ค„๋กœ index, show, new, create, edit, update, destroy 7๊ฐœ ๋ผ์šฐํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹

Params & Strong Parameters

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ ‘๊ทผ๊ณผ ํ—ˆ์šฉ ๋ชฉ๋ก ๊ด€๋ฆฌ

params ํ•ด์‹œ๋กœ URL ํŒŒ๋ผ๋ฏธํ„ฐ, ํผ ๋ฐ์ดํ„ฐ, JSON ๋ฐ”๋””์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. Strong Parameters(require/permit)๋กœ ํ—ˆ์šฉ๋œ ํ•„๋“œ๋งŒ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹์œผ๋กœ ํ†ต๊ณผ์‹œ์ผœ Mass Assignment ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

โฑ๏ธ

Before Action & Callbacks

์•ก์…˜ ์‹คํ–‰ ์ „ํ›„์— ๊ณตํ†ต ๋กœ์ง์„ ๋ผ์›Œ๋„ฃ๋Š” ๋ฐฉ๋ฒ•

before_action, after_action, around_action์œผ๋กœ Controller ์•ก์…˜ ์‹คํ–‰ ์ „ํ›„์— ๊ณตํ†ต ๋กœ์ง(์ธ์ฆ ํ™•์ธ, ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋“ฑ)์„ ์„ ์–ธ์ ์œผ๋กœ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿงฉ

Controller Concerns

์—ฌ๋Ÿฌ Controller์—์„œ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“ˆ

app/controllers/concerns/ ํด๋”์— ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด ์—ฌ๋Ÿฌ Controller์—์„œ includeํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ธ์ฆ, ํŽ˜์ด์ง€๋„ค์ด์…˜, ๊ฒ€์ƒ‰ ๋“ฑ ๊ณตํ†ต ๊ธฐ๋Šฅ์— ํ™œ์šฉ.

๐Ÿ—„๏ธ Models & Database

๐Ÿ’Ž

ActiveRecord

ORM โ€” ๊ฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐ์ž‘

Object-Relational Mapping. Ruby ๊ฐ์ฒด์™€ DB ํ…Œ์ด๋ธ”์„ ์ž๋™ ๋งคํ•‘ํ•˜์—ฌ, SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  Ruby ๋ฉ”์„œ๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ CRUDํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ฆ

Migrations (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜)

์ฝ”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋ฅผ ๋ฒ„์ „ ๊ด€๋ฆฌ

Ruby ์ฝ”๋“œ๋กœ DB ํ…Œ์ด๋ธ” ์ƒ์„ฑ/์ˆ˜์ •/์‚ญ์ œ๋ฅผ ์ •์˜ํ•˜๊ณ , ์‹œ๊ฐ„์ˆœ์œผ๋กœ ์‹คํ–‰ํ•˜์—ฌ ์Šคํ‚ค๋งˆ๋ฅผ ๋ฒ„์ „ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. Git์ฒ˜๋Ÿผ DB ๋ณ€๊ฒฝ ์ด๋ ฅ์„ ์ถ”์ ํ•˜๊ณ  ๋กค๋ฐฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”—

Associations (๊ด€๊ณ„)

has_many, belongs_to โ€” ๋ชจ๋ธ ๊ฐ„ ๊ด€๊ณ„ ์„ค์ •

belongs_to, has_many, has_one, has_many :through ๋“ฑ์œผ๋กœ ๋ชจ๋ธ ๊ฐ„ ๊ด€๊ณ„๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ž˜ํ‚ค ๊ทœ์•ฝ์„ ๋”ฐ๋ฅด๋ฉด ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

โœ…

Validations (์œ ํšจ์„ฑ ๊ฒ€์‚ฌ)

Model ๋ ˆ๋ฒจ์—์„œ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ

validates ๋งคํฌ๋กœ๋กœ ๋ชจ๋ธ์— ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. presence, uniqueness, length, format ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฒ€์ฆ์„ DB ์ €์žฅ ์ „์— ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿช

Model Callbacks

์ €์žฅ/์‚ญ์ œ ์ „ํ›„์— ์ž๋™ ์‹คํ–‰๋˜๋Š” ํ›…

before_save, after_create, before_destroy ๋“ฑ ๋ชจ๋ธ ๋ผ์ดํ”„์‚ฌ์ดํด ์ด๋ฒคํŠธ์— ํ›…์„ ๊ฑธ์–ด, ํŠน์ • ์‹œ์ ์— ์ž๋™์œผ๋กœ ๋กœ์ง์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž

Scopes & Query Interface

์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ด๋ฆ„ ๋ถ™์—ฌ ๊ด€๋ฆฌ

scope ๋งคํฌ๋กœ๋กœ ์ž์ฃผ ์“ฐ๋Š” ์ฟผ๋ฆฌ ์กฐ๊ฑด์— ์ด๋ฆ„์„ ๋ถ™์—ฌ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฒด์ด๋‹์ด ๊ฐ€๋Šฅํ•˜์—ฌ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋„ ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โš ๏ธ

N+1 ์ฟผ๋ฆฌ ๋ฌธ์ œ

์„ฑ๋Šฅ์˜ ์  โ€” includes๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•

์—ฐ๊ด€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต๋ฌธ์—์„œ ๊ฐœ๋ณ„ ์กฐํšŒํ•˜๋ฉด 1(๋ชฉ๋ก) + N(๊ฐ ํ•ญ๋ชฉ์˜ ์—ฐ๊ด€) ๋ฒˆ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. includes/preload/eager_load๋กœ 2๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽจ Views & Frontend

๐Ÿ“„

ERB & Partials

HTML ์•ˆ์— Ruby๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ , ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์กฐ๊ฐ์œผ๋กœ ๋ถ„๋ฆฌ

ERB(Embedded Ruby)๋Š” HTML ์•ˆ์— Ruby ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ์—”์ง„์ž…๋‹ˆ๋‹ค. Partial์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ทฐ ์กฐ๊ฐ์œผ๋กœ, ๋ฐ˜๋ณต์„ ์ค„์ด๊ณ  ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ–ผ๏ธ

Layouts & yield

ํŽ˜์ด์ง€์˜ ๊ณตํ†ต ๊ณจ๊ฒฉ์„ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๊ด€๋ฆฌ

application.html.erb ๋ ˆ์ด์•„์›ƒ์— ๊ณตํ†ต HTML ๊ตฌ์กฐ(head, nav, footer)๋ฅผ ์ •์˜ํ•˜๊ณ , yield๋กœ ๊ฐ ํŽ˜์ด์ง€์˜ ๊ณ ์œ  ๋‚ด์šฉ์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“

Form Helpers

form_with๋กœ ์•ˆ์ „ํ•˜๊ณ  ํŽธ๋ฆฌํ•œ ํผ ์ž‘์„ฑ

form_with ํ—ฌํผ๋กœ CSRF ํ† ํฐ, HTTP ๋ฉ”์„œ๋“œ, ํŒŒ๋ผ๋ฏธํ„ฐ ๋„ค์ด๋ฐ์„ ์ž๋™ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ฉด create/update URL๋„ ์ž๋™ ๊ฒฐ์ •.

โšก

Turbo & Hotwire

JavaScript ์—†์ด SPA ๊ฐ™์€ UX ๊ตฌํ˜„

Hotwire(HTML Over The Wire)๋Š” ์„œ๋ฒ„์—์„œ HTML์„ ๋ณด๋‚ด๊ณ  Turbo๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. JavaScript๋ฅผ ์ตœ์†Œํ™”ํ•˜๋ฉด์„œ SPA ์ˆ˜์ค€์˜ UX๋ฅผ ์ œ๊ณต.

๐ŸŽฎ

Stimulus

HTML ์ค‘์‹ฌ์˜ ๊ฒฝ๋Ÿ‰ JavaScript ํ”„๋ ˆ์ž„์›Œํฌ

HTML์— data-controller, data-action, data-target ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ JavaScript ๋™์ž‘์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. HTML์ด ์ฃผ๋„ํ•˜๊ณ , JS๋Š” "์–‘๋…" ์—ญํ• .

๐Ÿ” Authentication & Security

๐Ÿ”‘

Devise

Rails ํ‘œ์ค€ ์ธ์ฆ ์‹œ์Šคํ…œ

ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •, ์ด๋ฉ”์ผ ์ธ์ฆ, OAuth ๋“ฑ์„ ์ œ๊ณตํ•˜๋Š” ์ธ์ฆ gem. current_user, authenticate_user! ๋“ฑ ํ—ฌํผ๋ฅผ ์ž๋™ ์ƒ์„ฑ.

๐Ÿ›ก๏ธ

CSRF ๋ณดํ˜ธ

Cross-Site Request Forgery ๊ณต๊ฒฉ ์ž๋™ ๋ฐฉ์–ด

Rails๋Š” ๋ชจ๋“  non-GET ์š”์ฒญ์— CSRF ํ† ํฐ์„ ์ž๋™์œผ๋กœ ์‚ฝ์ž…/๊ฒ€์ฆํ•˜์—ฌ ์œ„์กฐ ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. protect_from_forgery๊ฐ€ ๊ธฐ๋ณธ ํ™œ์„ฑํ™”.

๐Ÿšซ

Strong Parameters

Mass Assignment ๊ณต๊ฒฉ ๋ฐฉ์ง€

Controller์—์„œ params.require(:model).permit(:field1, :field2)๋กœ ํ—ˆ์šฉํ•  ํ•„๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ํ•„๋“œ๋Š” ์ž๋™ ๋ฌด์‹œ.

๐Ÿ”’

ํ…Œ๋„ŒํŠธ ๋ถ„๋ฆฌ ์ฟผ๋ฆฌ ํŒจํ„ด โ€” Model.where ๋Œ€์‹  organization ์Šค์ฝ”ํ”„๋กœ ์‹œ์ž‘ํ•˜๊ธฐ

๋งˆ๋ฃจํ‹ฐํ…Œ๋„ŒํŠธ Rails ์•ฑ์—์„œ ๋ฐ์ดํ„ฐ ์œ ์ถœ์„ ๊ตฌ์กฐ์ ์œผ๋กœ ์ฐจ๋‹จํ•˜๋Š” ์ฟผ๋ฆฌ ์ž‘์„ฑ๋ฒ•

๋งˆ๋ฃจํ‹ฐํ…Œ๋„ŒํŠธ ์•ฑ์—์„œ Contract::Asset.joins(:contract).where(contracts: { organization_id: ... }) ๊ฐ™์€ ๊ทธ๋กœ๋ฒŒ ์ฟผ๋ฆฌ๋Š” ID ํ•˜๋‚˜ ์ž˜๋ชป ๋„˜๊ธฐ๋ฉด ๋‹ค๋ฅธ ์กฐ์ง์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํŠ€์–ด๋‚˜์˜จ๋‹ค. organization.contracts์—์„œ ์‹œ์ž‘ํ•˜๋ฉด ์ฟผ๋ฆฌ ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ํ…Œ๋„ŒํŠธ ๋ถ„๋ฆฌ๋ฅผ ๋ณด์žฅํ•œ๋‹ค.

๐Ÿงช Testing

๐Ÿงช

RSpec

BDD(Behavior-Driven Development) ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

describe/context/it ๋ธ”๋ก์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž์—ฐ์–ด์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. expect(์‹ค์ œ๊ฐ’).to eq(๊ธฐ๋Œ€๊ฐ’) ๋ฌธ๋ฒ•์œผ๋กœ ๊ฒ€์ฆํ•˜๋ฉฐ, Rails์˜ ๋ชจ๋“  ๊ณ„์ธต์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿญ

FactoryBot

ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ƒ์„ฑ

Fixture ๋Œ€์‹  Factory ํŒจํ„ด์œผ๋กœ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. create(:user), build(:post) ๋“ฑ ๊ฐ„๊ฒฐํ•œ ๋ฌธ๋ฒ•์œผ๋กœ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฆ‰์„์—์„œ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๐ŸŒ

Request Specs

HTTP ์š”์ฒญ/์‘๋‹ต์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

get, post, patch, delete ๋ฉ”์„œ๋“œ๋กœ ์‹ค์ œ HTTP ์š”์ฒญ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ , ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ, ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ, ๋ Œ๋”๋ง๋œ ๋‚ด์šฉ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

๐Ÿš€ Advanced

โณ

Background Jobs

Active Job + Sidekiq โ€” ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ

์ด๋ฉ”์ผ ๋ฐœ์†ก, ํŒŒ์ผ ์ฒ˜๋ฆฌ, ์™ธ๋ถ€ API ํ˜ธ์ถœ ๋“ฑ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ์— ๋„ฃ์–ด ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์ฆ‰์‹œ ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๐Ÿ’€

Sidekiq: ๋ฆด๋ฆฌ์Šค์™€ ๋น„๋™๊ธฐ ์žก์˜ ํ•จ์ •

SIGTERM/SIGKILL โ€” ๊ธด Sidekiq ์žก์ด ๋ฐฐํฌ ๋•Œ๋งˆ๋‹ค ์ฃฝ๋Š” ์ด์œ 

๋น„๋™๊ธฐ ์žก์ด ๋ฐฐํฌ ํƒ€์ด๋ฐ์— ๋”ฐ๋ผ ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง€๊ฑฐ๋‚˜ status๊ฐ€ ์˜์›ํžˆ \"์‹คํ–‰์ค‘\" ์œผ๋กœ ๊ณ ์ฐฉ๋  ์ˆ˜ ์žˆ๋‹ค. SIGTERM(์šฐ์•„ํ•œ ์ข…๋ฃŒ)๊ณผ SIGKILL(๊ฐ•์ œ ์ข…๋ฃŒ)์˜ ์ฐจ์ด, Sidekiq์˜ graceful shutdown ๋™์ž‘, OSS์˜ ํ•œ๊ณ„๋ฅผ ์ดํ•ดํ•˜๋ฉด ์™œ ์ด๋Ÿฐ ์‚ฌ๊ณ ๊ฐ€ ๋‚˜๋Š”์ง€ ๋ณด์ธ๋‹ค.

๐Ÿ“ก

Action Cable

Rails ๋‚ด์žฅ WebSocket โ€” ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ ๊ตฌํ˜„

Rails์— ๋‚ด์žฅ๋œ WebSocket ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ฑ„ํŒ…, ์•Œ๋ฆผ, ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ์— ํ™œ์šฉ.

๐Ÿ’จ

Caching (์บ์‹ฑ)

๋ฐ˜๋ณต ์—ฐ์‚ฐ์„ ์ค„์—ฌ ์‘๋‹ต ์†๋„๋ฅผ ๊ทน์ ์œผ๋กœ ํ–ฅ์ƒ

Fragment Caching, Russian Doll Caching, Low-Level Caching ๋“ฑ์œผ๋กœ DB ์ฟผ๋ฆฌ์™€ ๋ทฐ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜์—ฌ ์‘๋‹ต ์†๋„๋ฅผ ์ˆ˜์‹ญ ๋ฐฐ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“ฆ

Asset Pipeline & Vite

JavaScript, CSS, ์ด๋ฏธ์ง€ ๋“ฑ ํ”„๋ก ํŠธ์—”๋“œ ์—์…‹ ๊ด€๋ฆฌ

Sprockets(์ „ํ†ต), Webpacker(ํ์ง€), Vite(์ตœ์‹ )๋กœ JavaScript/CSS/์ด๋ฏธ์ง€๋ฅผ ๋ฒˆ๋“ค๋งํ•˜๊ณ , ํ•‘๊ฑฐํ”„๋ฆฐํŒ…์œผ๋กœ ์บ์‹œ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿšข

Kamal ๋ฐฐํฌ

Rails ๊ณต์‹ ๋ฐฐํฌ ๋„๊ตฌ โ€” Docker ๊ธฐ๋ฐ˜ ์ œ๋กœ ๋‹ค์šดํƒ€์ž„ ๋ฐฐํฌ

DHH๊ฐ€ ๋งŒ๋“  Rails ๊ณต์‹ ๋ฐฐํฌ ๋„๊ตฌ. Docker ์ปจํ…Œ์ด๋„ˆ๋กœ ์–ด๋–ค VPS์—๋“  ๋ฐฐํฌ ๊ฐ€๋Šฅ. DigitalOcean ๋“ฑ ์†Œ๊ทœ๋ชจ ์„œ๋ฒ„์—์„œ๋Š” ๋กœ์ปฌ ๋นŒ๋“œ ํ›„ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— pushํ•˜๋Š” ๋ฐฉ์‹์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ–ผ๏ธ

background-removal-js โ€” ๋ธŒ๋ผ์šฐ์ €์—์„œ AI๋กœ ๋ฐฐ๊ฒฝ์„ ์ œ๊ฑฐํ•˜๋Š” ์›๋ฆฌ

IS-Net ๋ชจ๋ธ + ONNX Runtime Web + WebGPU, ์„œ๋ฒ„ ์—†์ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜

imgly/background-removal-js๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์„œ๋ฒ„ ์—†์ด AI๋กœ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ์„ ์ œ๊ฑฐํ•œ๋‹ค. IS-Net(U-Net ๊ณ„์—ด) ๋ชจ๋ธ์„ ONNX Runtime Web์œผ๋กœ ์‹คํ–‰ํ•˜๋ฉฐ, WebGPU ๊ฐ€์†๋„ ์ง€์›ํ•œ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ 1024ร—1024๋กœ ๋ฆฌ์‚ฌ์ด์ฆˆ โ†’ ๋ชจ๋ธ์ด ์•ŒํŒŒ๋งˆ์Šคํฌ ์ถœ๋ ฅ โ†’ ์›๋ณธ์— ์ ์šฉํ•˜๋Š” ๊ตฌ์กฐ.

๐Ÿ“– Rails Open Source ์ฝ”๋“œ ์ฝ๊ธฐ

๐Ÿ”ฅ

Campfire (37signals)

DHH ์Šคํƒ€์ผ์˜ ๊ต๊ณผ์„œ โ€” Rails ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๋งŒ์œผ๋กœ ๋งŒ๋“  ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ์•ฑ

37์‹œ๊ทธ๋„์Šค๊ฐ€ ONCE ๋ธŒ๋žœ๋“œ๋กœ ์ถœ์‹œํ•œ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ์•ฑ. Devise ์—†์ด has_secure_password, Redis ์—†์ด Solid ์‹œ๋ฆฌ์ฆˆ, ์ปค์Šคํ…€ ์•ก์…˜ ์—†์ด CRUD๋งŒ์œผ๋กœ ๊ตฌํ˜„๋œ DHH ์Šคํƒ€์ผ์˜ ๊ต๊ณผ์„œ.

๐Ÿ“–

Writebook (37signals)

ONCE ๋ธŒ๋žœ๋“œ์˜ ์ถœํŒ ๋„๊ตฌ โ€” delegated_type๊ณผ ํŽธ์ง‘ ์ด๋ ฅ ๊ด€๋ฆฌ์˜ ๊ต๊ณผ์„œ

37์‹œ๊ทธ๋„์Šค์˜ ONCE ๋ธŒ๋žœ๋“œ ์ถœํŒ ์•ฑ. delegated_type์œผ๋กœ ๋‹คํ˜•์„ฑ ์ฝ˜ํ…์ธ (Page/Section/Picture)๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , Edit ๋ ˆ์ฝ”๋“œ๋กœ ํŽธ์ง‘ ์ด๋ ฅ์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. Campfire์™€ ๊ฐ™์€ ์ธ์ฆ ํŒจํ„ด์ด์ง€๋งŒ, ์ ‘๊ทผ ์ œ์–ด(Access)์™€ ์ถœํŒ(Publication) ๊ฐ™์€ ๋…์ž์  ํŒจํ„ด๋„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‹

Solid Queue (Rails)

Redis ์—†์ด DB๋งŒ์œผ๋กœ โ€” Rails 8 ๊ธฐ๋ณธ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์žก ์‹œ์Šคํ…œ

Rails 8์˜ ๊ธฐ๋ณธ ActiveJob ๋ฐฑ์—”๋“œ. Redis/Sidekiq ๋Œ€์‹  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(PostgreSQL/MySQL/SQLite)๋งŒ์œผ๋กœ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์žก์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. FOR UPDATE SKIP LOCKED์œผ๋กœ ๋น„์ฐจ๋‹จ ํด๋ง ๊ตฌํ˜„.

๐Ÿ’พ

Solid Cache (Rails)

Redis ๋Œ€์‹  SSD โ€” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ธฐ๋ฐ˜ Rails ์บ์‹œ ์Šคํ† ์–ด

Rails 8์˜ ๊ธฐ๋ณธ ์บ์‹œ ์Šคํ† ์–ด. Redis/Memcached ๋Œ€์‹  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(SSD)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ›จ์”ฌ ํฐ ์บ์‹œ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์“ฐ๊ธฐ ๊ธฐ๋ฐ˜ ํ™•๋ฅ ์  ๋งŒ๋ฃŒ์™€ Maglev ์ผ๊ด€ ํ•ด์‹ฑ์œผ๋กœ ์ƒค๋”ฉ ์ง€์›.

๐Ÿ— Infra

๐Ÿ’Ž

Rails 8 + SQLite โ€” ํ”„๋กœ๋•์…˜์—์„œ ์จ๋„ ๋˜๋Š” ์ด์œ 

PostgreSQL ์—†์ด๋„ ๋˜๋Š” ์‹œ๋Œ€๊ฐ€ ์™”๋‹ค โ€” 37signals๊ฐ€ ์ฆ๋ช…ํ•œ SQLite ํ”„๋กœ๋•์…˜ ์šด์˜

Rails 8์€ SQLite๋ฅผ ํ”„๋กœ๋•์…˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๊ณต์‹ ์ง€์›ํ•œ๋‹ค. Solid Queue(๋ฐฑ๊ทธ๋ผ์šด๋“œ ์žก), Solid Cache(์บ์‹œ), Solid Cable(์›น์†Œ์ผ“)๊นŒ์ง€ ์ „๋ถ€ SQLite๋กœ ๋™์ž‘. 37signals(Basecamp)๊ฐ€ ์‹ค์ œ ํ”„๋กœ๋•์…˜์—์„œ ๊ฒ€์ฆํ–ˆ๋‹ค.

๐Ÿ“

SQLite WAL ๋ชจ๋“œ โ€” ์žฅ์ ๊ณผ ๋‹จ์ 

Write-Ahead Logging์ด SQLite์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š”๊ฐ€

WAL(Write-Ahead Logging)์€ SQLite์˜ ๊ธฐ๋ณธ DELETE ์ €๋„ ๋ชจ๋“œ๋ฅผ ๋Œ€์ฒดํ•˜์—ฌ reader์™€ writer์˜ ๋™์‹œ ์ ‘๊ทผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ๋ชจ๋“œ๋‹ค. Rails 8์—์„œ ๊ธฐ๋ณธ ํ™œ์„ฑํ™”๋˜๋ฉฐ, Solid Queue ๊ฐ™์€ ๋นˆ๋ฒˆํ•œ ์†Œ๊ทœ๋ชจ ํŠธ๋žœ์žญ์…˜ ํ™˜๊ฒฝ์—์„œ ํŠนํžˆ ํšจ๊ณผ์ ์ด๋‹ค.

๐Ÿš€

์ดˆ๊ธฐ Rails ์•ฑ ๋””ํ”Œ๋กœ์ด SaaS ๋น„๊ต

Fly.io, Render, DigitalOcean, Fargate, Railway, Heroku ๋“ฑ ์‹ค์ „ ๋น„๊ต

Rails ์ดˆ๊ธฐ ํ”„๋กœ์ ํŠธ๋ฅผ ๋””ํ”Œ๋กœ์ดํ•  ๋•Œ ์–ด๋–ค PaaS/SaaS๋ฅผ ์„ ํƒํ• ์ง€์— ๋Œ€ํ•œ ์‹ค์ „ ๊ฐ€์ด๋“œ. ๋ฌด๋ฃŒ ํ‹ฐ์–ด, Docker ์ง€์›, PostgreSQL/SQLite ํ˜ธํ™˜์„ฑ, ๊ฐ€๊ฒฉ ๊ตฌ์กฐ, ์Šค์ผ€์ผ๋ง ์˜ต์…˜์„ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ต.