Rebase

브랜치 간 병합하는 방법으로 merge 와 rebase 가 있다.
이번 포스팅에서는 rebase 가 어떤 원리로 수행되는지 정리한다.

동작 순서

  1. 첫 번째 브랜치에서 c1, c2, c3 커밋을 한다.
  2. 그리고, 두 번째 브랜치로 checkout 을 한뒤에 c4, c5 커밋을 한다.
  3. 그리고, 다시 첫 번째 브랜치로 checkout 을 하여 c6 커밋을 한다. 이 때, conflict 가 발생하도록 공통 부분을 수정하자.

여기까지의 상황을 그림으로 표현하면 다음과 같다.

이 상황에서, 두 번째 브랜치를 첫 번째 브랜치로 ‘re’base 시도하면 어떤 일이 발생할까 ?
conflict 가 발생한다. 위의 3번에서 공통 부분을 수정하였기 때문이다. 그래서, 개발자가 직접 conflict 발생 부분을 수정해줘야 병합을 계속 진행할 수 있다. 이것이 핵심이다. rebase 는 순차적으로 병합을 시도한다. 다음과 같이, c4 를 c6 까지의 결과에 병합을 시도하고, 이 병합된 결과에 c5 를 병합 시도한다.

예제

위와 같은 상황을 실제로 재현하여 직접 rebase 테스트를 해보자. 브랜치는 다음 두 개로 한다 : master, jko

  1. master 에서 test.txt 파일을 생성하고, “commit 1 by master” 내용을 기입하고 commit 한다.

  2. “commit 2 by master” 내용을 기입하고 commit 한다.

  3. “commit 3 by master” 내용을 기입하고 commit 한다. 지금까지의 상황을 확인해보자.

  4. 이제 jko 브랜치로 checkout 한다. head 는 jko 를 가리키고 있다.

  5. “commit 4 by jko” 내용을 기입하고 commit 한다.

  6. “commit 5 by jko” 내용을 기입하고 commit 한다. 지금까지의 상황을 확인해보자.

  7. 이제 conflict 를 발생시킬 것이다. master branch 로 checkout 를 하자. 파일에는 jko branch 에서 추가한 두 커밋 내용이 당연히 없다.

  8. “commit 3 by master” 을 ‘’will be conflict” 로 변경하고 커밋하자.

  9. master 와 jko 브랜치의 test.txt 파일 내용은 각각 다음과 같다.

  10. 이제 jko 브랜치로 checkout 하자. master 로 rebase 해보자. 다음과 같이 conflict 를 해결하고 rebase continue 를 진행하라고 나온다. 여기가 핵심이다.

  11. test.txt 파일을 열어보자. conflict 지점이 master 에서 ‘“will be conflict” 로 수정한 지점이다. 그런데 왜, jko branch 에서 커밋한 “commit 5 by jko” 내용이 없을까 ? 앞서 강조하였듯이, rebase 는 순차적으로 진행하기 때문이다. “commit 4 by jko” 까지의 내용을 master 브랜치로 병합하고 있기 때문에, 현재 conflict 가 발생한 파일에는 “commit 5 by jko” 내용이 없는것이다.
    이제, 빨간 박스 부분을 지우고, rebase 를 계속 진행하자.

Read more

Bean

Bean 이 무엇이고, Spring Boot 는 어떤 과정으로 Bean 을 등록되는지 정리한다.

Bean 이란

IoC (Inversion of Control) Container 가 관리하는 객체이다.
IoC Container 는 객체의 생성을 책임지고 의존성을 관리한다. Spring 에서는 ApplicaitonContext 가 IoC Container 역할을 한다. ApplicaitonContext 는 BeanFactory 를 확장한다.

Bean 등록 순서

다음 순으로 Bean 이 등록된다.

  1. @ComponentScan
    최상위 패키지 이하의 모든 패키지에 있는 클래스에, @Component 가 붙어있으면 Bean 으로 등록한다.
    예를 들어, 다음과 같이 repository package 와 service package 에 각각 @Repository, @Service 가 붙은 클래스는 Bean 으로 등록된다. @Repository, @Service 도 결국 @Component 가 붙어있기 때문이다.
    ( Bean 등록 대상은, IDE 에서 클래스 옆에 콩 모양의 이미지를 보여준다. )

  2. @EnableAutoConfiguration
    spring-boot-autoconfigure 프로젝트의 META-INF 에 spring.factories 라는 파일이 있다.
    이 파일 안의 key 값 중에 EnableAutoConfiguratoin 이라는 키가 있는데, 이 키에 여러 Configuration 클래스가 정의되어있다.

    그리고 각 Configuration 클래스에는 @Configuration 이 붙어있다.
    예를 들어, WebMvcAutoConfigurration 를 따라가보면 결국에는 @Component 가 붙어 있기 때문에 Bean 으로 등록된다.

Read more

Sync/Async, Blocking/Non-Blocking

Sync 와 Async 의 차이, Blocking 과 Non-Blocking 의 차이를 정리한다.

Sync 와 Async

메서드의 결과를 제공하는 Server 를 기준으로 생각해야한다.
Sync 는 다음 그림과 같이, 메서드의 결과과 결정되고 나서야 반환을 한다.

Async 는 다음 그림과 같이, 메서드의 결과가 결정되기 전에 반환을 한다.

Blocking 과 Non-Blocking

메서드를 호출하는 Client 를 기준으로 생각해야한다.
Blocking 은 다음 그림과 같이, 메서드를 호출하고 메서드의 결과를 return 받을 때 까지 다른 작업을 못한다.

Non-Blocking 은 메서드를 호출하고 다른 작업을 할 수 있다. 이는 call-back 을 통해 가능하다. 즉, 메서드의 결과를 제공하는 서버에서 결과가 완성되면 클라이언트에게 call-back 을 하는 것이다. 다음 그림과 같다.

Read more

Spring MVC 요청 처리 과정

Spring MVC 는 어떻게 Client 의 요청을 처리하는지에 대해 정리한다.

DispatcherServlet

DispatchServlet 은 Client 의 요청에 대해 실제 처리하는 메서드를 호출해주는 Front Controller 역할을 하는 클래스이다.
계층 구조는 다음과 같다.

이제, DispatchServlet 이 Client 의 요청을 받은 뒤에, 어떻게 요청을 처리할 Controller 를 찾고 응답하는지 알아보자.

Client 요청 처리 흐름

전체 흐름은 다음과 같다.

  1. Application 이 구동될 때, Spring Boot Auto Configure 로 Spring MVC 의 Bean 들이 자동 등록된다.
  2. 사용자의 요청이 들어오면, DispatcherServlet 의 doService() 가 실행된다.
  3. doService() 에서 여러 설정을 한 뒤, doDispatch() 가 실행이 된다.
  4. HandlerMapping 이 요청을 처리할 Handler 를 찾는다.
  5. 등록되어 있는 HandlerAdapter 중에 해당 Handler 를 실행할 Adapter 를 찾는다.
  6. HandlerAdapter 는 Handler 의 응답을 처리한다.
  7. 최종적으로 응답을 보낸다.

디버거를 이용해서, 위 흐름을 코드로 상세히 살펴보자.

  1. Client 가 GET 요청을 하면, FrameworkServlet 의 doGet() 이 실행된다.

  2. processRequest() 의 doService() 에 들어가자.

Read more

[테스트 주도 개발] 29장_xUnit 패턴

xUnit 계열의 테스트 프레임워크를 위한 패턴을 정리한다.

assertion

테스트가 어떻게 잘 작동하는지 테스트 할 것인가?
boolean 수식을 이용해서, 프로그램이 코드가 동작하는지 자동으로 판단하도록 해라.

fixture

여러 테스트에서 공통으로 사용하는 객체들을 생성할 때 어떻게 하면 좋을까?
각 테스트 코드의 지역 변수를 인스턴스 변수로 바꾸고 setUp() 메서드에 재정의해라. 그리고, setUp() 메서드에서 인스턴스 변수들을 초기화하도록 해라.

외부 fixture

픽스처 중에 외부 자원이 있을 경우에 어떻게 해제할 것인가?
tearDown() 메서드를 재정의해라. 그리고, teaDown() 메서드에서 자원을 해제하라.

테스트 메서드

테스트 케이스 하나를 어떻게 표현하나?
‘test’ 로 시작하는 이름의 메서드로 읽기 쉽도록 표현해라.

예외 테스트
Read more