CQRS Pattern

CQRS

Command Query Responsibility Segregation

  • ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํ˜ธ์ž‘์šฉ์— ๋Œ€ํ•œ ํŒจํ„ด

  • ๋ช…๋ น๊ณผ ์กฐํšŒ์˜ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜๋Š” ์›์น™์„ ๊ธฐ๋ฐ˜

  • ์ฝ๊ธฐ(Query)์™€ ์“ฐ๊ธฐ(Command) ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ

๊ธฐ์กด ์‹œ์Šคํ…œ ๋ฌธ์ œ์ 

  • ์กฐํšŒ์™€ ๋ช…๋ น์„ ํ•˜๋‚˜์˜ ๋ชจ๋ธ์—์„œ ์ฒ˜๋ฆฌ

  • ๋ฐ์ดํ„ฐ ๊ฒฝํ•ฉ ๋ฐœ์ƒ

  • ๋ณต์žก๋„ ์ฆ๊ฐ€

CQRS ์ด์ 

  • ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ(๋ช…๋ น)๊ณผ ์กฐํšŒ(์ฟผ๋ฆฌ)๋ฅผ ์„œ๋กœ ๋‹ค๋ฅธ ๋ชจ๋ธ๋กœ ๋ถ„๋ฆฌ ๋ฐ ์ฒ˜๋ฆฌ

  • ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ๊ณผ ์กฐํšŒ ๊ฐ„์˜ ์˜์กด์„ฑ ๊ฐ์†Œ

  • ์œ ์—ฐ์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ํ–ฅ์ƒ

  • ๋ณต์žกํ•œ ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด๋‚˜ ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ์—์„œ ์œ ์šฉ

  • ๋‹จ์ˆœํ•œ ์‹œ์Šคํ…œ์—์„œ๋Š” ์˜ค๋ฒ„์—”์ง€๋‹ˆ์–ด๋ง

CQRS์˜ ๊ตฌ์„ฑ ์š”์†Œ

๋ช…๋ น(Command)

  • ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์„ ์˜๋ฏธ

  • ๋ช…๋ น ๋ชจ๋ธ์€ ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ํ†ต์ง€ํ•œ๋‹ค.

์ฟผ๋ฆฌ(Query)

  • ์‹œ์Šคํ…œ์˜ ์ƒํƒœ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ž‘์—…์„ ์˜๋ฏธ

  • ์ฟผ๋ฆฌ ๋ชจ๋ธ์€ ์ฝ๊ธฐ ์ „์šฉ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์กฐํšŒ

์ด๋ฒคํŠธ(Event)

  • ์‹œ์Šคํ…œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ค‘์š”ํ•œ ์‚ฌ๊ฑด์ด๋‚˜ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ๋‚˜ํƒ€๋ƒ„

  • ๋ช…๋ น ๋ชจ๋ธ์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ํ•ด๋‹น ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ด๋ฒคํŠธ๋กœ ๊ธฐ๋ก

๋ช…๋ น ํ•ธ๋“ค๋Ÿฌ(Command Handler)

  • ๋ช…๋ น์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ

  • ๋ช…๋ น์„ ๋ฐ›์•„ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ด

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ(Event Handler)

  • ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ

  • ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ์ฟผ๋ฆฌ ๋ชจ๋ธ์„ ์—…๋ฐ์ดํŠธ

๋ช…๋ น๊ณผ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉ, ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ๋ฅผ ๋‹ค๋ฅธ ๋ชจ๋ธ๋กœ ๊ตฌ๋ถ„

๋†’์€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ์œ„ํ•ด ์“ฐ๊ธฐ, ์ฝ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๊ตฌ๋ถ„

Code

// ์ปค๋งจ๋“œ ๋ชจ๋ธ
class Command {
  private String data;
  
  public Command(String data) {
    this.data = data;
  }
  
  public String getData() {
    return data;
  }
}

// ์ฟผ๋ฆฌ ๋ชจ๋ธ
class Query {
  // ์กฐํšŒ์— ํ•„์š”ํ•œ ํ•„๋“œ ๋ฐ ๋ฉ”์„œ๋“œ๋“ค...
}

// ๋ช…๋ น ํ•ธ๋“ค๋Ÿฌ
class CommandHandler {
  public void handleCommand(Command command) {
    //๋ช…๋ น์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋Š” ๋กœ์ง
  }
}

// ์กฐํšŒ ํ•ธ๋“ค๋Ÿฌ
class QueryHandler {
  public Query handleQuery() {
    // ์กฐํšŒ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋กœ์ง
    return new Query()
  }
}

// CQRS ์„œ๋น„์Šค
class CqrsService {
  private CommandHandler commandHandler;
  private QueryHandler queryHandler;
  
  public CqrsService(CommandHandler commandHandler, QueryHandler queryHandler) {
    this.commandHandler = commandHandler;
    this.queryHandler = queryHandler;
  }
  
  public void sendCommand(Command command) {
    commandHandler.handleCommand(command);
  }
  
  public Query sendQuery() {
    return queryHandler.handleQuery();
  }
}

// ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ
public class CqrsExample {
  public static void main(String[] args) {
    CommandHandler commandHandler = new CommandHandler();
    QueryHandler queryHandler = new QueryHandler();
    
    CqrsService cqrsService = new CqrsService(commandHandler, queryHandler);
    
    //๋ช…๋ น ๋ณด๋‚ด๊ธฐ
    Command command = new Command("Update data");
    cqrsService.sendCommand(command);
    
    //์กฐํšŒ ๋ณด๋‚ด๊ธฐ
    Query query = cqrsService.sendQuery();
    // ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง...
  }
}

Last updated