Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f5bed99
docs:CQRS 정리
DongLee99 Mar 22, 2021
346a594
feat:racingcar
DongLee99 Mar 23, 2021
a7717f0
docs:디미터 법칙
DongLee99 Mar 24, 2021
53f4584
refactor:0,10,4의 상수화
DongLee99 Mar 25, 2021
e066d5c
refactor:setMaxPostion네이밍 변경
DongLee99 Mar 25, 2021
72cd83a
refactor:getResult 들여쓰기 수정
DongLee99 Mar 25, 2021
d1ae117
refactor:게임 객체 책임 분리
DongLee99 Mar 25, 2021
1c4f320
refactor:run 들여쓰기 수정
DongLee99 Mar 25, 2021
86d8c4b
refactor:nextInt 네임 구체화
DongLee99 Mar 25, 2021
6e53c88
docs: 일급 컬렉션
DongLee99 Mar 26, 2021
9ce66ee
refactor:상속 삭제, setting 수정
DongLee99 Mar 28, 2021
be4583c
refactor:일급 컬렉션 사용
DongLee99 Mar 28, 2021
4277ed8
refactor:for -> peek,forEachorderd
DongLee99 Mar 28, 2021
010001f
refactor:Car 객체 검증
DongLee99 Mar 29, 2021
786596e
refactor:Cars,Number 객체 검증
DongLee99 Mar 29, 2021
5285a00
refactor:Cars 중복 체크 수정
DongLee99 Mar 29, 2021
ed1ecae
refactor:racingcar run 메소드 수정
DongLee99 Mar 30, 2021
3072302
docs : 기능 정리
DongLee99 Apr 5, 2021
fbe351b
refactor:Car 매직 넘버 컨벤션
DongLee99 Apr 7, 2021
45a2562
refactor:Cars if문 수정
DongLee99 Apr 7, 2021
d5a6b79
refactor:Number 불필요한 변수 할당 삭제
DongLee99 Apr 7, 2021
bf7ab0b
refactor:RandomUtils 컨벤션
DongLee99 Apr 7, 2021
d498254
refactor:Input spliterole 상수화
DongLee99 Apr 7, 2021
7900eb3
refactor:Input BufferReader 상수화
DongLee99 Apr 7, 2021
73619f2
refactor:코드 마지막에 빈줄 추가
DongLee99 Apr 7, 2021
703c7f4
refactor:findMaxPosition 불필요한 변수 할당 삭제
DongLee99 Apr 7, 2021
c675eda
refactor:MoveCars forEachOrderd -> forEach
DongLee99 Apr 7, 2021
4a38043
refactor:buffer 네이밍 수정
DongLee99 Apr 7, 2021
e8a53fd
refactor:Cars 생성자 수정
DongLee99 Apr 7, 2021
e5ed149
refactor:Winner 수정
DongLee99 Apr 7, 2021
eb1444a
refactor:View 문자 상수화
DongLee99 Apr 8, 2021
d0a0667
refactor:moveCar 랜덤값 파라미터로 넘겨주기, 인덴트 수정
DongLee99 Apr 13, 2021
3557aff
refactor : run 메소드 수정
DongLee99 Apr 27, 2021
3c73adc
refactor: for -> stream
DongLee99 Apr 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions 8week/CQRS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# CQRS

---

## CQRS 란?

- Command and Query Responsibility Segregation (명령과 조회의 책임 분리) 의 약자이며 이름 처럼 시스템의 명령을 처리하는 책임 / 조회를 처리하는 책임 분리

💁 명령 : CQRS 에서 시스템의 상태를 변경하는 작업

💁 조회 : CQRS 에서 시스템의 상태를 반환하는 작업

간단하게 CRUD ⇒ CUD / R

---

## 🤔 CQRS이 왜 생겨났는가?

- 전통적인 CRUD 아키텍쳐 기반에서 application 은 운영하다 보면 Domain Model 의 복잡도가 점점 증가 하고 이에 따라 유지 보수의 Cost 도 높아지며 Domain Model 의 변질까지 생기는 경우가 있다.

- 이에 DDD(Domain Model Design) 의 문제점을 해결하기 위해 CQRS가 생겨 나게 됐다.

---

## CQRS 예시

![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3d67082a-3273-4dd6-9096-89f51eeeaeb7/_2021-03-22__11.05.42.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3d67082a-3273-4dd6-9096-89f51eeeaeb7/_2021-03-22__11.05.42.png)

- 위 그림은 CQRS 가 적용되지 않은 애플리케이션의 모델이다. 이는 간단한 애플리케이션에는 적합하지만 복잡해 질수록 위에서 말했던 문제점이 발생되게 된다.
- 모양이 다른 DTO 의 반환
- 병렬작업시 경합 발생
- 정보 검색을 위한 쿼리의 복잡성으로 성능 저하
- 각 엔티티가 읽기 및 쓰기 작업의 대상이 되어 잘못된 데이터 노출

**CQRS 적용시**

![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/06c4bda0-0818-4ff7-b5c8-946e62fa02aa/_2021-03-22__11.25.12.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/06c4bda0-0818-4ff7-b5c8-946e62fa02aa/_2021-03-22__11.25.12.png)

- Read / Write 분리
- 명령 데이터 중심이 아닌 작업 기반
- 명령 동기 X 비동기
- 쿼리가 데이터 베이스 수정 X

읽기 저장소는 쓰기 저장소의 읽기 전용 복제본이거나 읽기 및 쓰기 저장소가 전혀 다른 구조일수 있다.

![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d2d90f98-1bc8-4c86-be49-f6c86e55581c/_2021-03-22__12.36.04.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d2d90f98-1bc8-4c86-be49-f6c86e55581c/_2021-03-22__12.36.04.png)

읽기 전용 복제본을 여러개 사용하면 읽기 전용 복제본이 응용 프로그램 인스턴스에 가까운 위치에 있는 분산 시나리오에서 쿼리 성능을 향상 시킬수 있다.

CQRS의 일부 구현에서는 이벤트 소싱 패턴 ( 각 이벤트의 변경에 대한 값을 저장 해놓는 집합 도메인은 현재 상태만 기록함 )을 사용한다. 이는 다른 구성요소를 알리는데 동일한 이벤트를 사용할수있다는 이점을 가지고 있고 쿼리보다 효과적이다. But 복잡성을 추가하게 된다.

---

## ? 그렇다면 CQRS 언제 사용을 할까

- 여러 사용자가 동일한 데이터를 동시에 엑세스하는 공동작업시
- 복잡한 도메인 모델을 사용하는 프로세스를 구현할때
- 데이터의 성능을 데이터 쓰기의 성능과 별도로 세부적으로 조정해야 할때
- 개발자가 쓰기, 읽기에 각각 집중을 할때

**권장 하지 않는 경우**

- 도메인, 비즈니스 규칙이 간단할때
- 간단한 CRUD 스타일로 작업이 충분할때

---

## Reference

[https://code-masterjung.tistory.com/80](https://code-masterjung.tistory.com/80)

[https://www.popit.kr/cqrs-eventsourcing/](https://www.popit.kr/cqrs-eventsourcing/)

[https://justhackem.wordpress.com/2016/09/17/what-is-cqrs/](https://justhackem.wordpress.com/2016/09/17/what-is-cqrs/)
21 changes: 21 additions & 0 deletions 8week/racingcar/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.DS_Store
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
/out/
/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
bin/

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
14 changes: 14 additions & 0 deletions 8week/racingcar/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
84 changes: 84 additions & 0 deletions 8week/racingcar/document/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# RacingCar 기능정리

---
## Domain

### Car
* 아는 것
* 차의 이름
* 차의 위치
* 랜덤 범위
* 하는 것
* 차 이동
* 이름 검증 (공백, 길이)

### Cars
* 아는 것
* 복수의 차
* 하는 것
* 차 전체 이동
* 가장 멀리간 차의 위치 찾기
* 우승자 찾기
* 차 이름 중복 검증

### Number
* 아는 것
* 숫자 값
* 하는 것
* 변수형 검

---

## Service

### RacingCarGame
* 아는 것
* 하는 것
* 게임 시작

### RacingCarGameController
* 아는 것
* 하는 것
* 차 생성
* count 생성
* 경주 실행

---

## Utils

### Input
* 아는 것
* 하는 것
* 숫자 입력
* 문자 입력

### RandomUtils
* 아는 것
* 랜덤 라이브러리
* 하는 것
* 범위 내의 랜덤값 생


### View
* 아는 것
* 하는 것
* 거리 출력
* 차 이름 출력
* 우승자 출력



보장된 숫자 입력

보장된 문자 입력

보장된 숫자가 아닐 시 에러가 발생한다.

자동차 이름 중복 제거

자동차 이름의 길이가 5이하 보장

범위내의 랜덤값 생성 보장

String 입력을 각 항목별 분리
Binary file added 8week/racingcar/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions 8week/racingcar/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
185 changes: 185 additions & 0 deletions 8week/racingcar/gradlew
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env sh

#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
echo "$*"
}

die () {
echo
echo "$*"
echo
exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

JAVACMD=`cygpath --unix "$JAVACMD"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option

if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

exec "$JAVACMD" "$@"
Loading