์ง๋์ฃผ์ ๊ธ์ ์ผ์ด์
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
}
๊ทธ๋ฌ๋ ์ค์ ํ๋ก์ ํธ์์๋ ์ ์ฅ์๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ ๊ฒฝ์ฐ ๋ ์ฝ๋ ๊ฒ์ ๋ฐฉ๋ฒ์ด ์ ์ฅ์์ ์ถ๊ฐ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}
์ด๋ฌํ ๋ฉ์๋๋ Eloquent ๋ฒ์๋ฅผ ํตํด ๊ตฌํ๋ ์ ์์ง๋ง ์ํฐํฐ ํด๋์ค์ ์์ ์ ๊ฐ์ ธ์ค๋ ์ฑ ์์ ์ค๋ฒ๋ก๋ํ๋ ๊ฒ์ ์ต์ ์ ์์ด๋์ด๊ฐ ์๋๋ฉฐ ์ด ์ฑ ์์ ์ ์ฅ์ ํด๋์ค๋ก ์ฎ๊ธฐ๋ ๊ฒ์ด ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ณด์ ๋๋ค. ๊ทธ๋ ์ต๋๊น? ์ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ด ์ธํฐํ์ด์ค๋ฅผ ์๊ฐ์ ์ผ๋ก ๋ ๋ถ๋ถ์ผ๋ก ๋๋์์ต๋๋ค. ๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ์ฐ๊ธฐ ์์ ์ ์ฌ์ฉ๋ฉ๋๋ค.
ํ์ค ์ฐ๊ธฐ ์์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์๋ก์ด ์ฌ๋ฌผ์ ๊ฑด์ค๊ณผ ๋์ PostRepository::์ ์ฅ
- PostRepository::getById, ๊ฐ์ฒด ์กฐ์ ๋ฐ ์ํ PostRepository::์ ์ฅ
- ๋์ PostRepository::์ญ์
์ฐ๊ธฐ ์์ ์์๋ ๊ฐ์ ธ์ค๊ธฐ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ์ฝ๊ธฐ ์์ ์์๋ get* ๋ฉ์๋๋ง ์ฌ์ฉ๋ฉ๋๋ค. ์ ๋ํด ์ฝ์ผ๋ฉด ์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์๋ฆฌ (ํธ์ง I ะฒ ๊ณ ์ฒด), ๊ทธ๋ฌ๋ฉด ์ฐ๋ฆฌ์ ์ธํฐํ์ด์ค๊ฐ ๋๋ฌด ํฌ๊ณ ์ ์ด๋ ๋ ๊ฐ์ง ๋ค๋ฅธ ์ฑ ์์ ์ํํ๋ค๋ ๊ฒ์ด ๋ถ๋ช ํด์ง ๊ฒ์ ๋๋ค. ์ด์ ๋ ๊ฐ๋ก ๋๋ ์ฐจ๋ก์ ๋๋ค. ๋ฐฉ๋ฒ getById ๋ ๊ฐ์ง ๋ชจ๋์ ํ์ํ์ง๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋์ฑ ๋ณต์กํด์ง๋ฉด ๊ตฌํ ๋ฐฉ์๋ ๋ฌ๋ผ์ง๋๋ค. ์ฐ๋ฆฌ๋ ์ด๊ฒ์ ์กฐ๊ธ ๋์ค์ ๋ณด๊ฒ ๋ ๊ฒ์ ๋๋ค. ์ด์ ๊ธ์์ ์ฐ๊ธฐ ๋ถ๋ถ์ ์ธ๋ชจ์์์ ๋ํด ์ผ๊ธฐ ๋๋ฌธ์ ์ด๋ฒ ๊ธ์์๋ ๊ทธ๋ฅ ์์ด๋ฒ๋ฆฌ๊ฒ ์ต๋๋ค.
์ฝ๊ธฐ ๋ถ๋ถ์ ๊ทธ๋ค์ง ์ธ๋ชจ๊ฐ ์๋ ๊ฒ ๊ฐ์ต๋๋ค. Eloquent์ ๊ฒฝ์ฐ์๋ ์ฌ๊ธฐ์ ์ฌ๋ฌ ๊ตฌํ์ด ์์ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์์ ์ด๋ฆ์ ๋ฌด์์ผ๋ก ํ ๊น์? ํ ์ ์๋ค ์ฝ๊ธฐํฌ์คํธ์ ์ฅ์, ๊ทธ๋ฌ๋ ํ ํ๋ฆฟ์ ์ ์ฅ์ ๊ทธ๋ ์ด๋ฏธ ๊ด๋ จ์ฑ์ด ๊ฑฐ์ ์์ต๋๋ค. ๋น์ ์ ํ ์ ์์ต๋๋ค ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ:
<?php
interface PostQueries
{
public function getById($id): Post;
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}
Eloquent๋ก ๊ตฌํํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค:
<?php
final class EloquentPostQueries implements PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
/**
* @return Post[] | Collection
*/
public function getLastPosts()
{
return Post::orderBy('created_at', 'desc')
->limit(/*some limit*/)
->get();
}
/**
* @return Post[] | Collection
*/
public function getTopPosts()
{
return Post::orderBy('rating', 'desc')
->limit(/*some limit*/)
->get();
}
/**
* @param int $userId
* @return Post[] | Collection
*/
public function getUserPosts($userId)
{
return Post::whereUserId($userId)
->orderBy('created_at', 'desc')
->get();
}
}
์ธํฐํ์ด์ค๋ ๊ตฌํ๊ณผ ์ฐ๊ฒฐ๋์ด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฑ ์๋น์ค ์ ๊ณต์:
<?php
final class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostQueries::class,
EloquentPostQueries::class);
}
}
์ด ์์ ์ ์ด๋ฏธ ์ ์ฉํฉ๋๋ค. ๊ทธ๋ ์ปจํธ๋กค๋ฌ๋ ์ํฐํฐ ํด๋์ค๋ฅผ ๊ตฌ์ ํจ์ผ๋ก์จ ์์ ์ ์ฑ ์์ ๊นจ๋ซ์ต๋๋ค. ์ปจํธ๋กค๋ฌ์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
<?php
final class PostsController extends Controller
{
public function lastPosts(PostQueries $postQueries)
{
return view('posts.last', [
'posts' => $postQueries->getLastPosts(),
]);
}
}
๋ฐฉ๋ฒ PostsController::lastPosts ๊ตฌํ์ ์์ฒญํ๋ ์ค์ ๋๋ค. ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ ๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ผ๋ก ์ผํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ฐ๊ฒฐํ ๊ณต๊ธ์์์ ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ ์์ ๊ณผ ํจ๊ป EloquentPost์ฟผ๋ฆฌ ์ด ํด๋์ค๋ ์ปจํธ๋กค๋ฌ๋ก ๋์ฒด๋ฉ๋๋ค.
์ฐ๋ฆฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋งค์ฐ ์ธ๊ธฐ๋ฅผ ์ป์๋ค๊ณ ์์ํด ๋ด ์๋ค. ๋ถ๋น ์์ฒ ๋ช ์ ์ฌ์ฉ์๊ฐ ์ต์ ์ถํ๋ฌผ์ด ํฌํจ๋ ํ์ด์ง๋ฅผ ์ฝ๋๋ค. ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ์ถํ๋ฌผ๋ ๋งค์ฐ ์์ฃผ ์ฝํ์ง๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ด๋ฌํ ๋ก๋๋ฅผ ์ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฏ๋ก ํ์ค ์๋ฃจ์ ์ธ ์บ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์๋ ํน์ ๋ฐ์ดํฐ ์ค๋ ์ท์ ํน์ ์์ ์ ์ต์ ํ๋ ์คํ ๋ฆฌ์ง์ ์ ์ฅ๋ฉ๋๋ค. memcached ๋๋ ํ์ฑ.
์บ์ฑ ๋ก์ง์ ์ผ๋ฐ์ ์ผ๋ก ๊ทธ๋ค์ง ๋ณต์กํ์ง ์์ง๋ง EloquentPostQueries์์ ์ด๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๊ทธ๋ค์ง ์ ํํ์ง ์์ต๋๋ค(๋ค์๊ณผ ๊ฐ์ ์ด์ ๋๋ฌธ์). ๋จ์ผ ์ฑ ์ ์์น). ํ ํ๋ฆฟ์ ์ฌ์ฉํ๋ ๊ฒ์ด ํจ์ฌ ๋ ์์ฐ์ค๋ฝ์ต๋๋ค. ๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ณธ ์์ ์ ์ฅ์์ผ๋ก ์บ์ฑ์ ๊ตฌํํฉ๋๋ค.
<?php
use IlluminateContractsCacheRepository;
final class CachedPostQueries implements PostQueries
{
const LASTS_DURATION = 10;
/** @var PostQueries */
private $base;
/** @var Repository */
private $cache;
public function __construct(
PostQueries $base, Repository $cache)
{
$this->base = $base;
$this->cache = $cache;
}
/**
* @return Post[] | Collection
*/
public function getLastPosts()
{
return $this->cache->remember('last_posts',
self::LASTS_DURATION,
function(){
return $this->base->getLastPosts();
});
}
// ะดััะณะธะต ะผะตัะพะดั ะฟัะฐะบัะธัะตัะบะธ ัะฐะบะธะต ะถะต
}
์ธํฐํ์ด์ค๋ฅผ ๋ฌด์ํ์ธ์ ์ ์ฅ์ ์์ฑ์์์. ์ ์ ์๋ ์ด์ ๋ก ๊ทธ๋ค์ Laravel์์ ์บ์ฑ์ ์ํ ์ธํฐํ์ด์ค ์ด๋ฆ์ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ง์ ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
ํด๋์ค ์บ์๋ ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ ์บ์ฑ๋ง ๊ตฌํํฉ๋๋ค. $this->์บ์->๊ธฐ์ตํ๊ธฐ ์ด ํญ๋ชฉ์ด ์บ์์ ์๋์ง ํ์ธํ๊ณ ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ์ฝ๋ฐฑ์ ํธ์ถํ๊ณ ๋ฐํ๋ ๊ฐ์ ์บ์์ ์๋๋ค. ๋จ์ ๊ฒ์ ์ด ํด๋์ค๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌํํ๋ ๊ฒ๋ฟ์ ๋๋ค. ์ธํฐํ์ด์ค ๊ตฌํ์ ์์ฒญํ๋ ค๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ ๋ชจ๋ ํด๋์ค๊ฐ ํ์ํฉ๋๋ค. ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๋ฐ๊ธฐ ์์ํ์ต๋๋ค ์บ์๋ ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ. ๊ทธ๋ฌ๋ ๊ทธ ์์ ์ ์บ์๋ ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ ์์ฑ์๋ ํด๋์ค๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์์ผ ํฉ๋๋ค. EloquentPost์ฟผ๋ฆฌ"์ค์ " ๊ตฌํ ์์ด๋ ์๋ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋ณํํ๋ค ์ฑ ์๋น์ค ์ ๊ณต์:
<?php
final class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostQueries::class,
CachedPostQueries::class);
$this->app->when(CachedPostQueries::class)
->needs(PostQueries::class)
->give(EloquentPostQueries::class);
}
}
๋ด ๋ชจ๋ ์์์ ๊ณต๊ธ์์๊ฒ ์์ฃผ ์์ฐ์ค๋ฝ๊ฒ ์ค๋ช ๋์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ํ๋์ ํด๋์ค๋ฅผ ์์ฑํ๊ณ ์ปจํ ์ด๋ ๊ตฌ์ฑ์ ๋ณ๊ฒฝํ๋ ๊ฒ๋ง์ผ๋ก ์์ฒญ์ ๋ํ ์บ์ฑ์ ๊ตฌํํ์ต๋๋ค. ๋๋จธ์ง ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ ๋ณ๊ฒฝ๋์ง ์์์ต๋๋ค.
๋ฌผ๋ก ์บ์ฑ์ ์๋ฒฝํ๊ฒ ๊ตฌํํ๊ธฐ ์ํด์๋ ์ญ์ ๋ ๊ธ์ด ์ฌ์ดํธ์ ํ๋์ ๋จธ๋ฌผ์ง ์๊ณ ๋ฐ๋ก ์ญ์ ๋๋๋ก ๋ฌดํจํ๋ ๊ตฌํํด์ผ ํ๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ๋ค์ ์ฌ์ํ ๊ฒ๋ค์ ๋๋ค.
๊ฒฐ๋ก : ์ฐ๋ฆฌ๋ ํ๋๊ฐ ์๋ ๋ ๊ฐ์ ํ ํ๋ฆฟ์ ์ฌ์ฉํ์ต๋๋ค. ๊ฒฌ๋ณธ CQRS(๋ช ๋ น ์ฟผ๋ฆฌ ์ฑ ์ ๋ถ๋ฆฌ) ์ธํฐํ์ด์ค ์์ค์์ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ์์ ์ ์์ ํ ๋ถ๋ฆฌํ ๊ฒ์ ์ ์ํฉ๋๋ค. ๋๋ ๊ทธ๋ฅผ ํตํด ๊ทธ์๊ฒ ์์ต๋๋ค ์ธํฐํ์ด์ค ๋ถ๋ฆฌ ์๋ฆฌ, ์ด๋ ํจํด๊ณผ ์๋ฆฌ๋ฅผ ๋ฅ์ํ๊ฒ ์กฐ์ํ๊ณ ํ๋๋ฅผ ์ ๋ฆฌ๋ก ๋์ถํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค :) ๋ฌผ๋ก ๋ชจ๋ ํ๋ก์ ํธ์ ์ํฐํฐ๋ฅผ ์ ํํ๊ธฐ ์ํด ์ด๋ฌํ ์ถ์ํ๊ฐ ํ์ํ ๊ฒ์ ์๋์ง๋ง ๊ทธ ์๋ น์ ์ฌ๋ฌ๋ถ๊ณผ ๊ณต์ ํ๊ฒ ์ต๋๋ค. ๊ฐ๋ฐ, ๊ฐ๋จํ ํด๋์ค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ Eloquent๋ฅผ ํตํ ์ผ๋ฐ์ ์ธ ๊ตฌํ:
<?php
final class PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
// ะดััะณะธะต ะผะตัะพะดั
}
์บ์ฑ์ด ํ์ํ ๋ ๊ฐ๋จํ ์ด๋์ผ๋ก ์ด ํด๋์ค ๋์ ์ธํฐํ์ด์ค(๋๋ ์ถ์ ํด๋์ค)๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๊ฒ์๋ฌผ ์ฟผ๋ฆฌ, ํด๋น ๊ตฌํ์ ํด๋์ค์ ๋ณต์ฌํฉ๋๋ค. EloquentPost์ฟผ๋ฆฌ ์์ ์ค๋ช ํ ๊ตฌ์ฑํ๋ก ์ด๋ํฉ๋๋ค. ๋๋จธ์ง ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ ๋ณ๊ฒฝํ ํ์๊ฐ ์์ต๋๋ค.
ํด๋์ค, ์ธํฐํ์ด์ค, ์์กด์ฑ ์ฃผ์
ะธ CQRS ์ ์์ธํ ์ค๋ช
์ถ์ฒ : habr.com