๐ก ์๋ณธ ๊ธ: https://blog.appsignal.com/2020/08/05/introduction-to-ruby-on-rails-patterns-and-anti-patterns.html
Ruby On Rails ํจํด ๋ฐ ์ํฐํจํด ์๋ฆฌ์ฆ์ ์ฒซ ๋ฒ์งธ ๊ฒ์๋ฌผ์ ์ค์ ๊ฒ์ ํ์ํฉ๋๋ค. ์ด ์๋ฆฌ์ฆ์์๋ Rails ์ฑ์ ๊ฐ๋ฐํ๋ ๋์ ์ ํ ์ ์๋ ๋ชจ๋ ์ข ๋ฅ์ ํจํด์ ๋ํด ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ค๋ ์ฐ๋ฆฌ๋ (๋์์ธ) ํจํด์ด ๋ฌด์์ธ์ง ๋ณด์ฌ์ฃผ๊ณ ์ํฐํจํด์ด ๋ฌด์์ธ์ง ์ค๋ช ํ๋ ค๊ณ ๋ ธ๋ ฅํ ๊ฒ ์ ๋๋ค. ์ค๋ช ์ ๋ํ ์ดํด๋ฅผ ๋์ด๊ธฐ ์ํด, ์ค๋ ์ญ์ฌ๋ฅผ ๊ฐ์ง Ruby on Rails ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ช ํ๊ฒ ์ต๋๋ค. ๋น์ ์ด Rails๋ฅผ ์ ํธํ์ง ์๋๋ผ๋ ๊ด์ฐฎ์ต๋๋ค. ์ฌ๊ธฐ ๋ค๋ฃจ๋ ์์ด๋์ด(๋๋ ํจํด)๋ค์ ๋ค๋ฅธ ๊ธฐ์ ์์๋ ์ ์ฉํ๊ฒ ํ์ฉ๋ ์ ์์ต๋๋ค.
ํ์ง๋ง ํจํด๊ณผ ์ํฐํจํด์ ๋ํด ์ค๋ช ํ๊ธฐ ์ ์, ์ ๋จผ์ ์ฐ๋ฆฌ๊ฐ ์ด๋ฐ ๊ฐ๋ ๋ค์ด ํ์ํ ์ด์ ๊ฐ ๋ฌด์์ผ๊น์? ์ํํธ์จ์ด๋ ์ด๋ฌํ ๊ฒ์ด ํ์ํ ์ด์ ๊ฐ ๋ฌด์์ผ๊น์? ์ฐ๋ฆฌ ์๋ฃจ์ ์ ์ ๋์์ธ(์ค๊ณ)๊ฐ ํ์ํ ๊น์?
๋ง์ต๋๋ค. ๋น์ ์ ๋์์ด๋์ ๋๋ค.
์ปดํจํฐ ํ๋ก๊ทธ๋๋ฐ ์ด๊ธฐ๋ถํฐ ์ฌ๋๋ค์ ์์ ์ด ์์ฑํ๋ ํ๋ก๊ทธ๋จ์ ๋์์ธ(์ค๊ณ)๋ฅผ ์ง์ ๋ค๋ฃจ์ด์ผ ํ์ต๋๋ค. ํ๋ก๊ทธ๋จ(๋๋ ์ํํธ์จ์ด)๋ฅผ ์์ฑํ๊ณ , ๋์์ธ(์ค๊ณ)ํ๋ค๋ ๊ฒ์ ๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ์ ์ํ๋ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ํํธ์จ์ด๋ฅผ ์์ฑํ๋ ๋์, ์ฐ๋ฆฌ๋ ๋์์ด๋์ ๋๋ค. ์ด๋ฅผ ์ง์์ ์์ ๋กญ๊ฒ ์ถ๊ฐํ์ธ์. ์ฐ๋ฆฌ๊ฐ ์์ฑํ ์ํํธ์จ์ด๋ ๋ค๋ฅธ์ฌ๋๋ค์ด ์ฝ๊ณ ์์ ํ ์ ์์ผ๋ฏ๋ก ์ข์ ํด๊ฒฐ์ฑ ์ผ๋ก ๋์์ธ(์ค๊ณ)ํ๋๊ฒ์ด ์ค์ํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ๋ง๋ค์ด๋ธ ํด๊ฒฐ์ฑ ๋ค์ ๋ฏธ๋์ ๋ ๋ค๋ฅธ ์ฌ๋๋ค์ด ๋ฐ์ ์์ผ ๋๊ฐ ๊ฒ์ ๋๋ค.
๊ฒฝํ ๋ง์ ์์ง๋์ด๋ค์ด ๊ฒฝ๋ ฅ์ ์์ผ๋ฉด์ ์ฝ๋์ ์ํคํ ์ฒ์์ ์ ์ฌํ ์ค๊ณ ํจํด์ ๋ฐ๋ณตํด์ ๋ณด๊ฒ๋๋ค. ์ด๋ฅผ ์ถ์ถํ์ฌ ๋ฌธ์ํํ๋ฉฐ ํ์ค ํด๊ฒฐ์ฑ ์ ๋ง๋ค์ด ๋ธ๋ค. ์ด๋ ์ธ๊ฐ์ ์ธ์ง ๊ธฐ๋ฅ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ ๋ณด์ฌ์ฃผ๋ ์์์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋ณด๋ ๊ฒ์์ ์นดํ ๊ณ ๋ผ์ด์ง(๊ท์น)๊ณผ ํจํด์ ์ฐพ๊ธฐ๋ฅผ ์ข์ํ๋ฉฐ, ์ํํธ์จ์ด ๊ฐ๋ฐ๋ ์์ธ๋ ์๋๋ค.
์ฐ๋ฆฌ ์ธ๊ฐ์ ๋ณธ๋ฅ์ธ ํจํด ์ฐพ๊ธฐ๋ ์ํํธ์จ์ด ์์ง๋์ด๋ง์ด ์ ์ ๋ณต์กํด์ง์ ๋ฐ๋ผ ๋์ฑ ๋๋๋ฌ์ง๋๋ค.์ฑ , ๊ธ, ๊ฐ์ฐ ๋ฑ์ ํตํด ์ ๊ณ ์๋๊ณ ์ค์ ์์ ๊ฒ์ฆ๋ ํด๊ฒฐ์ฑ ์ ๋ํ ์์ด๋์ด๊ฐ ๋์ฑ ํ์ฐ๋๋ฉด์, ์ํํธ์จ์ด ์ค๊ณ๋ ์ ์ธ๊ณ ์์ง๋์ด๋ค ์ฌ์ด์์ ๋ฐ์ ํ๊ณ ์๋ฆฌ์ก๊ธฐ ์์ํ์ต๋๋ค. ์ด๋ฌํ ํด๊ฒฐ์ฑ ์ ๋ง์ ์ฌ๋๋ค์ ์๊ฐ๊ณผ ๋น์ฉ์ ์ ์ฝํด์ฃผ์์ผ๋ฏ๋ก, ์ด์ ์ค๊ณ ํจํด์ด๋ผ๋ ์ฉ์ด๋ฅผ ์ดํด ๋ณด๊ณ ๊ทธ ๋ณธ์ง์ด ๋ฌด์์ธ์ง ์์๋ณด๊ฒ ์ต๋๋ค.
๋์์ธ ํจํด์ด๋ ๋ฌด์์ธ๊ฐ?
์ํํธ์จ์ด ์์ง๋์ด๋ง์์ ํจํด์ ๊ณตํต๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํด๊ฒฐ์ฑ ์ ์๋ฏธํฉ๋๋ค. ํจํด์ ์ํํธ์จ์ด ์์ง๋์ด๋ค ์ฌ์ด์์ ์ผ๋ฐ์ ์ผ๋ก ์ข์ ๊ดํ์ผ๋ก ์ฌ๊ฒจ์ง๋๋ค. ํ์ง๋ง ํจํด์ ์๋ชป ์ ์ฉ๋ ๊ฒฝ์ฐ ์ํฐํจํด์ด ๋ ์๋ ์์ต๋๋ค. ์ํฐํจํด์ ๋์ค์ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค.
๋์์ธ ํจํด์ ํด๊ฒฐ์ฑ ์ ๋ฐฉํฅ์ ์ ์ํ์ง๋ง, ์ฝ๋ ์กฐ๊ฐ์ ์ ๊ณตํ์ง ์์ต๋๋ค. ํจํด์ ์ ์ค๊ณ๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ ๊ฐ์ด๋์ด๋ฉฐ, ๊ตฌํ๊น์ง๋ ์ ๊ณตํ์ง ์์ต๋๋ค. ์ผ์์ ์ธ ์ฝ๋ฉ์์ ํจํด์ ์ฌ์ฉํ๋ ๊ฒ์ 1980๋ ๋ ํ๋ฐ์ ๋ฑ์ฅํ์ผ๋ฉฐ, Kent Back๊ณผ Ward Cunningham์ด ‘ํจํด ์ธ์ด’๋ฅผ ์ฌ์ฉํ๋ ์์ด๋์ด๋ฅผ ์ ์ํ์ต๋๋ค.
์ด ํจํด ์ธ์ด์ ์์ด๋์ด๋ 1970๋ ๋ ํ๋ฐ Christopher Alexander์ ์ ์์ธ A pattern Language์์ ์ฒ์ ๋ฑ์ฅํ์์ต๋๋ค. ๋๋๊ฒ๋ ์ด ์ฑ ์ ์ํํธ์จ์ด ์์ง๋์ด๋ง์ด ์๋๋ผ ๊ฑด์ถ์ ๊ดํ ์ฑ ์ ๋๋ค. ํจํด ์ธ์ด๋ ์ฒด๊ณ์ ์ด๊ณ ์ผ๊ด์ฑ ์๋ ํจํด์ ์งํฉ์ด๋ฉฐ, ๊ฐ.ํจํด์ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ฌ์ฉ๋ ์ ์๋ ๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ํต์ฌ์ ์ค๋ช ํฉ๋๋ค. ๋ญ๊ฐ ์ต์ํ๊ฒ ๋ค๋ฆฌ์ง ์๋์? (์: ํ๋ ์์ํฌ, Rails)
์ดํ ์ํํธ์จ์ด ์์ง๋์ด๋ง์ ๋์์ธ ํจํด์ 1994๋ ์ถํ๋ Gang Of Four์ ์ ์ค์ ์ธ ์ฑ Design Partterns๋ฅผ ํตํด ๋์ค์๊ฒ ๋๋ฆฌ ์๋ ค์ง๊ฒ ๋์์ต๋๋ค. ์ด ์ฑ ์๋ ํ์ฌ ์ฌ์ฉ๋๊ณ ์๋ Factory, Singleton, Decorator ๋ฑ์ ํจํด์ ๋ํ ์ค๋ช ๊ณผ ์ ์๊ฐ ๋์ ์์ต๋๋ค.
์ด์ ๋์์ธ ํจํด์ ๋ํ ์ง์์ ์ตํ๊ฑฐ๋ ๋์๊ฒผ์ผ๋, ์ํฐ ํจํด์ด ๋ฌด์์ธ์ง ์์๋ณด๊ฒ ์ต๋๋ค.
์ํฐํจํด์ด๋ ๋ฌด์์ธ๊ฐ?
๋ง์ฝ ํจํด์ ์ข์ ์ฉ์ฌ๋ผ๊ณ ์๊ฐํ๋ค๋ฉด, ์ํผํจํด์ ์ ๋น์ด๋ผ๊ณ ํ . ์์์ต๋๋ค. ์ข ๋ ์ ํํ๊ฒ ๋งํ์๋ฉด, ์ํํธ์จ์ด์ ์ํฐํจํด์ ํํ ์ฌ์ฉ๋์ง๋ง ๋น ํจ์จ์ ์ด๋ ๋น ์์ฐ์ ์ธ ํจํด์ ์๋ฏธํฉ๋๋ค. ์ํฐํจํด์ ๋ํ์ ์ธ ์๋ก๋ ๋ง์ ํจ์์ ์์กด์ฑ์ ํฌํจํ๊ณ ์์ด ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋ถ๋ฆฌํ ์ ์๋ God ๊ฐ์ฒด๊ฐ ์์ต๋๋ค.
์ฝ๋์์ ์ํฐํจํด์ด ๋ฐ์ํ๋ ๊ฒฝ์ฐ๋ ๋ค์ํฉ๋๋ค. ์๋ฅผ๋ค์ด ์ ํ ์ฉ์ฌ(ํจํด)๊ฐ ์ ๋น(์ํฐํจํด)์ด ๋๋ ๊ฒฝ์ฐ์ ๋๋ค. ์ด์ ํ์ฌ์์ ํน์ ๊ธฐ์ ์ ์ฌ์ฉํด์ ๋์ ์์ค์ ์ ๋ฌธ์ฑ์ ์์๋ค๊ณ ํด๋ด ์๋ค. ์๋ฅผ๋ค์ด Docker๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค. ๋น์ ์ Docker ์ปจํ ์ด๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํจ์จ์ ์ผ๋ก ํจํค์งํ๊ณ , ํด๋ผ์ฐ๋์์ ์ค์ผ์คํธ๋ ์ด์ ํ๊ณ , ํด๋ผ์ฐ๋์์ ๋ก๊ทธ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ์ ์๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ์๊ธฐ ๋๊ฐ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ถ์ํด์ผ ํ๋ ์ ์ง์ฅ์ ์ทจ์งํ๊ฒ ๋์์ต๋๋ค. Docker๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ์๊ธฐ ๋๋ฌธ์ ์ฒซ ๋ฒ์งธ ์ ๋ฌด๋ ๋ชจ๋ ๊ฒ์ ํจํค์งํด์ ํด๋ผ์ฐ๋์ ๋ฐฐํฌํ๋ ๊ฒ์ ๋๋ค.
ํ์ง๋ง, ํ๋ก ํธ์๋ ์ฑ์ด ๊ทธ๋ค์ง ๋ณต์กํ์ง ์์ผ๋ฉฐ ์ด๋ฅผ ์ปจํ ์ด๋์ ๋ฃ๋ ๊ฒ์ด ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ํด๊ฒฐ์ฑ ์ด ์๋ ์ ์์ต๋๋ค. ์ฒ์์๋ ์ข์ ์์๋ก ๋ค๋ฆด์ ์์ง๋ง, ๋์ค์๋ ๋น ์์ฐ์ ์ธ ๊ฒ์ผ๋ก ํ๋ช ๋๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ์ํฐํจํด์์๋ Golden Hammer(ํฉ๊ธ ๋ง์น)๋ผ๊ณ ๋ถ๋ฆฝ๋๋ค.
์ด๋ “๋ง์น๋ฅผ ๊ฐ์ง ์ฌ๋์๊ฒ๋ ๋ชจ๋ ๊ฒ์ด ๋ชป์ผ๋ก ๋ณด์ธ๋ค”๋ผ๋ ์๋ด์ผ๋ก ์์ฝํ ์ ์์ต๋๋ค. ๋ง์ฝ Docker์ ์๋น์ค ์ค์ผ์คํธ๋ ์ด์ ์ ์ ๋ง ๋ฅ์ํ๋ค๋ฉด, ๋ชจ๋ ๊ฒ์ด ํด๋ผ์ฐ๋์์ ์ค์ผ์คํธ๋ ์ด์ ์ด ๋๋๋ก ๋ง๋ค์ด์ง Docker ์๋น์ค๊ฐ ๋ฉ๋๋ค.
์ด๋ฐ ์ผ์ ์ข ์ข ๋ฐ์ํฉ๋๋ค. ์ ํ ์ฉ์ฌ๊ฐ ์ ๋น์ผ๋ก ๋ณํ๊ธฐ๋ ํ๊ณ , ๊ทธ ๋ฐ๋๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ํ์ง๋ง Ruby์ Rails๋ ์ด ๊ทธ๋ฆผ์์ ์ด๋ค ์์น์ ์์๊น์?
๋จผ์ Ruby, ๊ทธ ๋ค์์ Rails
๋๋ถ๋ถ ์ฌ๋๋ค์ ๋น ๋ฅด๊ฒ ์น ์ฌ์ดํธ๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด Ruby On Rails๋ฅผ ์ฌ์ฉํ์ฌ Ruby๋ฅผ ๋ฐฐ์ฐ๊ฒ ๋ฉ๋๋ค. ์ ๋ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก Ruby๋ฅผ ๋ฐฐ์ฐ๊ฒ ๋์๊ณ , ์ด๋ ๋์๊ฒ ์๋๋๋ค. Rails๋ ์ ์ ๋ฆฝ๋ ์ํํธ์จ์ด ํจํด์ธ MVC(Model-View-Controller)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค. ํ์ง๋ง Rails์์ MVC ํจํด์ ์ธ๋ถ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์ ํํ ๋ฐ์ํ๋ ํฐ ์ค๋ฅ๋ Ruby๋ฅผ ์ ๋๋ก ๋ฐฐ์ฐ์ง ์๊ณ Rails๋ง์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
Rails ํ๋ ์์ํฌ๋ ์์ด๋์ด๊ฐ ๋ ์ฌ๋์ ๋ ๋น ๋ฅด๊ฒ ๊ตฌํํ๊ธฐ ์ํ ์ต๊ณ ์ ์ ํ ์ค ํ๋์์ต๋๋ค. ์ค๋๋ Rails๋ ์ฌ์ ํ ์ฌ์ฉ๋๊ณ ์์ง๋ง ์ต์ ์ฑ๊ธฐ ๋งํผ์ ์ธ๊ธฐ๋ฅผ ์ ์งํ์ง ๋ชปํ๊ณ ์์ต๋๋ค. ์ฌ์ฉ๊ณผ ์คํ์ด ๋งค์ฐ ๊ฐ๋จํ๋ค๋ ์ ๋๋ฌธ์ ๋ง์ ์ด๋ณด์๋ค์ด rails new ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ ์น์ฑ ๊ฐ๋ฐ์ ์์ํฉ๋๋ค. ํ์ง๋ง ์๊ฐ์ด ์ง๋๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ ์์ํฉ๋๋ค. ์ด๋ณด์๋ก์ Rails์ ๋น ๋ฅด๊ณ ๊ฐ๋จํ ๊ฐ๋ฐ ์๋์ ๋งค๋ฃ๋๊ณ ์ฒ์์๋ ๋ชจ๋ ๊ฒ์ด ๋ง๋ฒ์ฒ๋ผ ์ํ ํ๊ฒ ์๋ํฉ๋๋ค. ํ์ง๋ง ์๊ฐ์ด ์ง๋๋ฉด ‘๋ง๋ฒ’์ ๋๋ฌด ์์กดํ๊ฒ ๋๊ณ ํ๋ ์์ํฌ ๋ด๋ถ์์ ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ์ดํดํ์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค.
์ ๋ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ์ง์ ๊ฒช์๊ณ , ๋ง์ ์ด๋ณด์์ ์ค๊ธ ๊ฐ๋ฐ์๋ค์ด ์ด๋ก ์ธํด ๊ณ ํต์ ๋ฐ๊ณ ์๋ค๋ ๊ฒ์ ํ์ ํฉ๋๋ค. ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ์ ์์ํ๊ณ ๊ทธ ์์ ๊ธฐ๋ฅ์ ์์ ๊ฐ๋ค๊ฐ, ๊ณ ๋๋ก ๋ง์ถคํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ค๊ณ ํ ๋, ํ๋ ์์ํฌ์ ๋ง๋ฒ์ ๋ค ์จ๋ฒ๋ ธ๊ธฐ ๋๋ฌธ์ ๋ ์ด์ ์งํํ ์ ์๊ฒ ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ์ด ์์ ์์ ๋๋์๊ฐ์ ๊ธฐ๋ณธ์ ๋ฐฐ์ฐ๋ ๊ฒ์ ์ด๋ ค์ด์ผ์ด ์๋๋๋ค. ๋๊ตฌ์๊ฒ๋ ์ผ์ด๋ ์ ์๋ ์ผ์ ๋๋ค. ํ์ง๋ง Ruby์ ๊ฐ์ ํ์์ ์ธ ์ฌํญ์ ๋ฐฐ์ฐ์ง ์๊ณ ์์ผ๋ก ๋์๊ฐ๋ฉด ๋ฌธ์ ๊ฐ ๋์ฑ ์ฌ๊ฐํด์ง๋๋ค. ์ด์ ๊ด๋ จํ์ฌ ์ถ์ฒํ๋ ์ข์ ์ฑ ์ “The Well-Grounded Rubyist” ์ ๋๋ค.
์ด๋ณด์๋ผ๋ฉด ์ฒ์๋ถํฐ ๋๊น์ง ๋ค ์ฝ์ ํ์๋ ์์ต๋๋ค. ํ์ง๋ง ๊ถ๊ธํ ๋๋ง๋ค ์ฝ๊ฒ ์ฐธ๊ณ ํ ์ ์๋๋ก ๊ฐ๊น์ด์ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ชจ๋ ๊ฒ์ ๋ฉ์ถ๊ณ ์ฑ ์ ์ฒด๋ฅผ ์ฝ์ผ๋ผ๊ณ ํ๋ ๊ฒ์ด ์๋๋ผ, ๊ฐ๋์ ๋ฉ์ถ์ด Ruby ๊ธฐ๋ณธ ์ง์์ ๋์๊ธฐ๋ ๊ฒ์ด ์๋ก์ด ์งํ์ ์ด์ด์ค ์ ์์ต๋๋ค
MVC: Rails์ ๋นต๊ณผ ๋ฒํฐ
์ข์์ ๊ทธ๋ผ MVC๋ ์ด๋ค๊ฐ์? Model-View-Controller ํจํด์ ์ค๋ซ๋์ ์ฌ์ฉ๋์ด ์์ต๋๋ค. Python(Djnago), Java(Play, Spring MVC), Ruby(Rails) ๋ฑ๊ณผ ๊ฐ์ ๋ค์ํ ๋ง์ ํ๋ ์์ํฌ์์ ์ฑํ๋์์ต๋๋ค. ์ด ํจํด์ ํต์ฌ์ ๊ฐ์ ๊ณ ์ ํ ์ญํ ์ ์ํํ๋ ๋ถ๋ฆฌ๋ ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ์ ๊ฒ์ ๋๋ค.:
- Model์ ๋ฐ์ดํฐ์ ๋น์ง๋์ค ๋ชจ๋ธ์ ์ฒ๋ฆฌํฉ๋๋ค.
- View๋ ๋ฐ์ดํฐ์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ํํ์ ๋ด๋นํฉ๋๋ค.
- Controller๋ Model์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ View๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค์ผ๋ก์จ ์ด ๋ ๊ฐ์ง๋ฅผ ํ๋๋ก ์ฐ๊ฒฐํฉ๋๋ค.
์ด๋ก ์ ์ผ๋ก๋ ํผ๋ฅญํ๊ฒ ๋ค๋ฆฌ๋ฉฐ, ๋ก์ง์ด ์ต์ํ๋๊ณ ์น์ฌ์ดํธ์ ๋ณต์กํ ๋ก์ง์ด ์์ ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ํ์ง๋ง ๋ก์ง์ด ๋ณต์กํด์ง๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉฐ ๊น๋ค๋ก์์ง๋ ๋ถ๋ถ์ด ์๊ธฐ๋๋ฐ ์ด์ ๋ํด์๋ ๊ณง ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
MVC๋ ์น ๊ฐ๋ฐ ์ปค๋ฎค๋ํฐ ์ ๋ฐ์ ๊ฑธ์ณ ๊ธ์๋๋ก ํผ์ ธ๋๊ฐ์ต๋๋ค. ์์ฆ ๋ฏธ์น๋ฏ์ด ์ธ๊ธฐ ์๋ React์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์กฐ์ฐจ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ View ๊ณ์ธต์ผ๋ก ์ค๋ช ๋ฉ๋๋ค. ๊ทธ ์ด๋ค ํจํด๋ ๋์คํ๋์ด ๋จ์ณ๋ฒ๋ฆด ์ ์๋ ํจํด์ ์์ต๋๋ค. Rails๋ ActionCable์ Publish-Subscribe๋ฅผ ์ถ๊ฐํ๋๋ฐ ์ฌ๊ธฐ์ ์ฑ๋์ ๊ฐ๋ ์ MVC ํจํด์ ์ปจํธ๋กค๋ฌ๋ก ์ค๋ช ์ด ๊ฐ๋ฅํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ ๊ฒ ๋๋ฆฌ ์ฌ์ฉ๋๋ ํจํด์์ ์ํฐํจํด์ ๋ฌด์์ผ๊น์? MVC ํจํด์ ๊ฐ ๋ถ๋ถ๋น ๋ํ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ํฐ ํจํด์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Model ๋ฌธ์
์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ฑฐ๋ํด์ง๊ณ ๋น์ง๋์ค ๋ก์ง์ด ์๋ผ๋ ์๋ก ์ฌ๋๋ค์ ๋ชจ๋ธ์ ๊ณผํ๊ฒ ์ฑ์๋ฃ๋ ๊ฒฝํฅ์ด ์์ต๋๋ค. ์ด๋ฌํ ์ง์์ ์ธ ์ฆ๊ฐ๋ ‘Fat Model’์ด๋ผ๋ ์ํฐํจํด์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
์ ๋ช ํ ‘Fat Model, Skinny Controller’ ํจํด์ ์ผ๋ถ์์๋ ์ ํ ์ฉ์ฌ๋ก ์ผ๋ถ์์๋ ์ ๋น์ผ๋ก ์ฌ๊ฒจ์ง๋๋ค. ์ฐ๋ฆฌ๋ ๋ฑ๋ฑํจ(fat) ์์ฒด๊ฐ ์ํฐํจํด์ด๋ผ๊ณ ๋งํ ๊ฒ ์ ๋๋ค. ์ดํด๋ฅผ ๋๊ธฐ ์ํด ์์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. Spotify ๋๋ Deezer์ ๊ฐ์ ์คํธ๋ ๋ฐ ์๋น์ค๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค. ์ด ์๋น์ค์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋ ธ๋ ๋ชจ๋ธ์ด ์์ต๋๋ค:
class Song < ApplicationRecord
belongs_to :album
belongs_to :artist
belongs_to :publisher
has_one :text
has_many :downloads
validates :artist_id, presence: true
validates :publisher_id, presence: true
after_update :alert_artist_followers
after_update :alert_publisher
def alert_artist_followers
return if unreleased?
artist.followers.each { |follower| follower.notify(self) }
end
def alert_publisher
PublisherMailer.song_email(publisher, self).deliver_now
end
def includes_profanities?
text.scan_for_profanities.any?
end
def user_downloaded?(user)
user.library.has_song?(self)
end
def find_published_from_artist_with_albums
...
end
def find_published_with_albums
...
end
def to_wav
...
end
def to_mp3
...
end
def to_flac
...
end
end
์ด์ ๊ฐ์ ๋ชจ๋ธ์ ๋ฌธ์ ์ ์ ๋ ธ๋์ ๊ด๋ จ๋ ๋ค์ํ ๋ก์ง์ ์ฐ๋ ๊ธฐ์ฅ์ด ๋๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ฉ์๋๊ฐ ํ๋์ฉ ์ฒ์ฒํ ์ถ๊ฐ๋๋ฉด์ ๋ฐ์ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ ์ฒด ๋ชจ๋ธ์ด ํฌ๊ณ ๋ณต์กํด ๋ณด์ด๋ฏ๋ก ๋ก์ง์ ๋ค๋ฅธ ๋ช ๊ตฐ๋ฐ๋ก ๋ถํ ํ๋ฉด ๋์ค์ ๋์์ด ๋ ์ ์์ต๋๋ค.
์ด ๋ชจ๋ธ์ด ์๋ฐํ๊ณ ์๋ ๋ช ๊ฐ์ง ๊ถ์ฅ ์ฌ๋ก๊ฐ ์์ต๋๋ค. ์ด ๋ชจ๋ธ์ ๋จ์ผ ์ฑ ์ ์์น(SRP)๋ฅผ ์๋ฐํ๊ณ ์์ต๋๋ค.
ํ๋ก์ฐ์ ๊ฒ์์์๊ฒ ์๋ฆผ์ ๋ณด๋ด๋ ์์ ์ ๋ค๋ฃน๋๋ค. ํ ์คํธ์์ ์์ค์ ํ์ธํ๊ณ , ๋ ธ๋๋ฅผ ๋ค๋ฅธ ์ค๋์ค ํ์์ผ๋ก ๋ด๋ณด๋ด๋ ๋ฐฉ๋ฒ ๋ฑ์ด ์์ต๋๋ค. ์ด ๋ชจ๋ ๊ฒ์ด ๋ชจ๋ธ์ ๋ณต์ก์ฑ์ ์ฆ๊ฐ์ํค๋ฉฐ, ์ด ๋ชจ๋ธ์ ํ ์คํธ ํ์ผ์ ์์์กฐ์ฐจ ํ ์ ์์ต๋๋ค.
์ด ๋ชจ๋ธ์ ๋ฆฌํฉํ ๋งํ๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ก ๋ค๋ฅธ ์์น์์ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์์ด๋์ด๋ฅผ ์ ์ํ๊ณ ๊ทํ์ ๊ฒฝ์ฐ์ ๊ฐ์ฅ ์ ํฉํ ๊ฒ์ ์ ํํ ์ ์์ต๋๋ค.
ํ๋ก์์ ๊ฒ์์์๊ฒ ์๋ฆฌ๋ ์ฝ๋ฐฑ์ Job์ผ๋ก ์ถ์ถ๋ ์ ์์ต๋๋ค. Job์ด ๋๊ธฐ์ด์ ์ถ๊ฐ๋๊ณ ๋ก์ง์ด ๋ชจ๋ธ์์ ์ ์ธ๋ฉ๋๋ค:
class NotifyFollowers < ApplicationJob
def perform(followers)
followers.each { |follower| follower.notify }
end
end
class NotifyPublisher < ApplicationJob
def perform(publisher, song)
PublisherMailer.song_email(publisher, self).deliver_now
end
end
Job์ ๋ชจ๋ธ๊ณผ ๋ณ๊ฐ๋ก ๋ณ๋์ ํ๋ก์ธ์ค์์ ์์ฒด์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ด์ Job ๋ก์ง์ ๋ณ๋๋ก ํ ์คํธํ๊ณ ๋ชจ๋ธ์์ ์ ์ ํ Job์ด ๋๊ธฐ์ด์ ์ถ๊ฐ๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์์ค ํ์ธ๊ณผ ์ฌ์ฉ์๊ฐ ๋ ธ๋๋ฅผ ๋ค์ด๋ก๋ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ์์ ์ด ๋ชจ๋ ์ฑ์ ๋ทฐ ๋ถ๋ถ์์ ๋ฐ์ํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ์ด ๊ฒฝ์ฐ Decorator ํจํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋น ๋ฅด๊ฒ ์์ํ ์ ์๋ ์ธ๊ธฐ์๋ ํด๊ฒฐ์ฑ ์ Draper gem์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ์ ์ํ Decorator๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
class SongDecorator < Draper::Decorator
delegate_all
def includes_profanities?
object.text.scan_for_profanities.any?
end
def user_downloaded?(user)
object.user.library.has_song?(self)
end
end
๊ทธ ๋ค์์, ์ปจํธ๋กค๋ฌ์์ decorate ๋ฅผ ํธ์ถํฉ๋๋ค. ์๋ฅผ๋ค๋ฉด ์๋์ ๊ฐ์ต๋๋ค:
def show
@song = Song.find(params[:id]).decorate
end
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด view์์ ์ฌ์ฉํด๋ณด์ธ์:
<%= @song.includes_profanities? %>
<%= @song.user_downloaded?(user) %>
๋ง์ฝ ๋๊ฐ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์์กด์ฑ์ ์ข์ํ์ง ์๋๋ค๋ฉด, ์ง์ decorator๋ฅผ ๋ง๋ค์๋ ์์ต๋๋ค. ์ด ๋ถ๋ถ์ ๋ค๋ฅธ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์์ ๋ค๋ฃฐ ์์ ์ ๋๋ค. ์ด์ ๋ชจ๋ธ์ ๋๋ถ๋ถ์ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ์ผ๋ฏ๋ก ๋ ธ๋๋ฅผ ์ฐพ๊ณ ๋ณํํ๋ ๋ฉ์๋๋ฅผ ์ฒ๋ฆฌ ํด๋ณด๊ฒ ์ต๋๋ค. ๋ชจ๋์ ์ฌ์ฉํ์ฌ ์ด๋ค์ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.
module SongFinders
def find_published_from_artist_with_albums
...
end
def find_published_with_albums
...
end
end
module SongConverter
def to_wav
...
end
def to_mp3
...
end
def to_flac
...
end
end
Song ๋ชจ๋ธ์ SongFinders ๋ชจ๋์ ํ์ฅํ๋ฏ๋ก ํด๋น ๋ฉ์๋๋ฅผ ํด๋์ค ๋ฉ์๋๋ก ์ฌ์ฉ ํ ์ ์์ต๋๋ค. Song ๋ชจ๋ธ์๋ SongConverter ๋ชจ๋์ด ํฌํจ๋๋ฏ๋ก ๋ชจ๋ธ ์ธ์คํด์ค์์ ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด ๋ชจ๋ ๊ฒ์ด ์ฐ๋ฆฌ์ Song ๋ชจ๋ธ์ ๋งค์ฐ ๋ ์ฌํ๊ณ ์๋ฒฝํ๊ฒ ๋ง๋ค์ด ์ค ๊ฒ์ ๋๋ค:
class Song < ApplicationRecord
extend SongFinders
include SongConverter
belongs_to :album
belongs_to :artist
belongs_to :publisher
has_one :text
has_many :downloads
validates :artist_id, presence: true
validates :publisher_id, presence: true
after_update :alert_artist_followers, if: :published?
after_update :alert_publisher
def alert_artist_followers
NotifyFollowers.perform_later(self)
end
def alert_publisher
NotifyPublisher.perform_later(publisher, self)
end
end
๋ ๋ง์ ์ํฐํจํด๋ค์ด ์์ผ๋ฉฐ ์ด๋ ๋ชจ๋ธ์ ํตํด ์ป์ ์ ์๋ ๊ฒ์ค์ ํ๋์ ์์์ผ ๋ฟ์ด์์ต๋๋ค. ์ด ์๋ฆฌ์ฆ์ ๋ค๋ฅธ ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ์ ๊ณ์ ์ง์ผ๋ด ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. ์ฌ๊ธฐ์ ๋ ๋ง์ ๋ชจ๋ธ ์ํฐ ํจํด์ ๋ํด์ ์์ธํ ์ค๋ช ํ๊ฒ ์ต๋๋ค. ์ง๊ธ์ view์ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
View ๋ฌธ์
๋ชจ๋ธ ๋ฌธ์ ์ธ์๋ Rails๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋๋ค์ ๋๋๋ก view์ ๋ณต์ก์ฑ์ผ๋ก ์ด๋ ค์์ ๊ฒช์ ์ ์์ต๋๋ค. ์์ ์๋ HTML๊ณผ CSS๊ฐ ์น์ ํ๋ฆฌ์ผ์ด์ view ๋ถ๋ถ์์ ์์ด์์ต๋๋ค. ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ JavaScript๊ฐ ์ง๋ฐฐํ๊ฒ ๋์๊ณ ํ๋ก ํธ์๋์ ๊ฑฐ์ ๋ชจ๋ ๋ถ๋ถ์ด JavaScript๋ก ์์ฑ๋์์ต๋๋ค. Rails๋ ์ด์ ์ฝ๊ฐ ๋ค๋ฅธ ํจ๋ฌ๋ค์์ ๋ฐ๋ฆ ๋๋ค. view์์ ๋ชจ๋ ๊ฒ์ JavaScript๋ก ์ ์งํ๋ ๋์ JS๋ฅผ “์ฝ๊ฐ๋ง” ๋ฟ๋ ค์ฃผ๋ ๊ฒ์ ๋๋ค.
์ด์จ๋ HTML, CSS, JS, Ruby๋ฅผ ํ ๊ณณ์ ๋ค๋ฃจ๋ ๊ฒ์ ๋ณต์กํด ์ง ์ ์์ต๋๋ค. Rails view๋ฅผ ๋ง๋๋๋ฐ ์ด๋ ค์ด ์ ์ ๋๋ฉ์ธ ๋ก์ง์ด ๋๋๋ก view ๋ด๋ถ์์ ์ฐพ์์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ MVC ํจํด์ ๊นจ๋จ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ฒ์๋ถํฐ ๊ธ์ง๋ ํ์์ ๋๋ค.
๋ ๋ค๋ฅธ ๊ฒฝ์ฐ๋ view์ ๋ถ๋ถ ํ ํ๋ฆฟ์ ๋๋ฌด ๋ง์ ์๋ฒ ๋๋ ruby๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ผ๋ถ ๋ก์ง์ ํฌํผ๋ ๋ฐ์ฝ๋ ์ดํฐ (view ๋ชจ๋ธ ๋๋ ํ๋ฆฌ์ ํฐ๋ผ๊ณ ํจ) ๋ด๋ถ์ ๋ค์ด ๊ฐ ์ ์์ต๋๋ค. ์ด์ ๋ํ ์์๋ ์ด ์๋ฆฌ์ฆ ๋ค์ ๊ฒ์๋ฌผ์์ ๋ค๋ฃฐ ์์ ์ด๋ ๊ณ์ ์ฃผ๋ชฉํด์ฃผ์ธ์.
Controller ๋ฌธ์
Rails ์ปจํธ๋กค๋ฌ ๋ํ ๋ค์ํ ๋ฌธ์ ์ ์๋ฌ๋ฆด ์ ์์ต๋๋ค. ๊ทธ ์ค ํ๋๊ฐ ‘Fat Controller’ ์ํฐ ํจํด์ ๋๋ค.
์ด์ ์๋ ๋ชจ๋ธ์ด ๋น๋ํด์ ์ฒด์ค์ ์ข ๊ฐ๋ํ๋๋ฐ, ์ด์ ๋ณด๋ ์ปจํธ๋กค๋ฌ๊ฐ ๊ทธ ๊ณผ์ ์์ ์ด์ด ์ฐ๊ฑฐ ๊ฐ์ต๋๋ค. ๋ณดํต ์ด๋ฐ ํ์์ ๋น์ง๋์ค ๋ก์ง์ด ํฐํธ๋กค๋ฌ ์์ ๋ค์ด์์ง๋ง, ์๋๋ ๋ชจ๋ธ์ด๋ ๋ค๋ฅธ ๊ณณ์ ์์ด์ผ ํ ๋ ๋ฐ์ํฉ๋๋ค. Fat Model ์์ญ์์ ๊ณต์ ๋ ์์ด๋์ด ์ค ์ผ๋ถ๋ ์ปจํธ๋กค๋ฌ์๋ ์ฌ์ ํ ์ ์ฉ๋ ์ ์์ต๋๋ค. presenter ์ฝ๋๋ก ์ถ์ถํ๊ณ , ActiveRecord ์ฝ๋ฐฑ์ ์ฌ์ฉํ๊ณ , ์๋น์ค ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
์ด๋ค ์ฌ๋๋ค์ Trailblazer๋ dry-transcation๊ณผ ๊ฐ์ ๋ณด์์ ์ฌ์ฉํ๊ธฐ๋ ํฉ๋๋ค. ์ฌ๊ธฐ์์ ์์ด๋์ด๋ ํน์ ํธ๋์ญ์ ์ ์ฒ๋ฆฌํ๋ ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. ๋ชจ๋ ๊ฒ์ ์ปจํธ๋กค๋ฌ ๋ฐ์ผ๋ก ์ฎ๊ธฐ๊ณ ๋ชจ๋ธ์ ๊ฐ๋ณ๊ฒ ์ ์งํ๋ฉด ์ด๋ฌํ ๋ณ๋์ ํด๋์ค ์์ ๋ก์ง์ ์ ์ฅํ๊ณ ํ ์คํธํ ์ ์์ต๋๋ค. ์ด ํด๋์ค๋ฅผ ์๋น์ค, ํธ๋์ญ์ , ์ก์ ๋ฑ์ผ๋ก ๋ถ๋ฆฝ๋๋ค.
๊ฒฐ๋ก
๋ ๋ง์ ์ํฐํจํด๊ณผ ์ด์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ต๋๋ค. ์ด ๊ฒ์๋ฌผ์์ ๋ชจ๋ ๋ด์ฉ์ ๋ค๋ฃจ๋ ค๊ณ ํ๋ฉด ๊ณต๊ฐ๊ณผ ์๊ฐ์ด ๋๋ฌด ๋ง์ด ๊ฑธ๋ฆฌ๊ณ ๋ฑ๋ฑํด ๋ณด์ผ๊ฒ์ ๋๋ค.(์ฐ๋ฆฌ๊ฐ ์ด์ผ๊ธฐํ ๋ชจ๋ธ ๋ฐ ์ปจํธ๋กค๋ฌ ์ฒ๋ผ) Rails MVC ํจํด์ ๋ชจ๋ ์ธก๋ฉด์ ์์ธํ ์์๋ณด๋ ์๋ฆฌ์ฆ๋ฅผ ๊ผญ ์์ฒญํด๋ณด์ธ์. ๊ฑฐ๊ธฐ์ ๊ฐ์ฅ ์ ๋ช ํ ์ํฐํจํด์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ฐ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋๊น์ง๋ ํจํด๊ณผ ์ํฐํจํด์ด ๋ฌด์์ธ์ง, ๊ทธ๋ฆฌ๊ณ Ruby On Rails ํ๋ ์์ํฌ์์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํจํด์ ๋ํ ๊ฐ์๋ฅผ ์ฌ๋ฏธ์๊ฒ ์ฝ์ผ์ จ๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋ค์ ์๊ฐ๊น์ง, ๊ฑด๋ฐฐ!
PS. Ruby Magic ๊ฒ์๋ฌผ์ด ๋ณด๋๋๋ ๋๋ก ์ฝ๊ณ ์ถ์ผ์๋ฉด Ruby Magic ๋ด์ค๋ ํฐ๋ฅผ ๊ตฌ๋ ํ์๊ณ ๋จ ํ๋์ ๊ฒ์๋ฌผ๋ ๋์น์ง ๋ง์ธ์!
'Backend > RubyOnRails' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ฒ์ญ] Ruby on Rails View Patterns and Anti-patterns(Ruby On Rails์ View์ ํจํด๊ณผ ์ํฐํจํด) (2) | 2024.01.11 |
---|---|
[๋ฒ์ญ] Ruby on Rails Model Patterns and Anti-patterns (Ruby On Rails์ ๋ชจ๋ธ์ ํจํด๊ณผ ์ํฐํจํด) (4) | 2024.01.04 |
NamedRoute์ _path vs _url (0) | 2022.08.15 |
devise_invitable๋ฅผ ํ ์คํธ ํด๋ณด์. (0) | 2022.02.19 |
Methods in Rails modules (0) | 2022.02.06 |