-
멘토링을 시작한지 2개월 차 블로그에 정리한 내용을 바탕으로 첫 모의면접을 실시했다.
Q: 트랜잭션이란 무엇인가 ?
A: 비지니스 로직에서 쪼개질 수 없은 하나의 단위작업으로 원자성, 일관성, 독립성, 영속성의 원칙을 지니고 있다.
+A: 데이터베이스는 기본적으로 트랜잭션을 관리하기 위한 설정을 가지고 있다. 데이터베이스에서는 명령이 끝날 때 까지 수행내역을 로그에 저장해두고 데이터베이스에 변경된 내용을 재반영하기 위한 redo.log와 수행에 실패에 있어서 이전상태로 되돌리는 undo.log를 이용해 트랜잭션을 지원한다. 하나의 작업 수행 목표를 위해 (ex) 송금의 경우 내 계좌에서 차감한 만큼 받는 계좌의 금액을 증가) 여러 명령을 묶어 비지니스 로직으로 하나의 트랜잭션으로 나타낸다. 성공적으로 수행되었을 경우 트랜잭션 커밋이 발생하여 수정된 내용을 데이터 베이스에 반영하게 된다. 하나의 명령이라도 실패하는 경우 모두 없던 일 처럼 모든 명령을 롤백하게 된다.
Q: 트랜잭션이 이루어지는 범위는?
A: 영속성 컨텍스트 생존 범위에서 영속상태, 수정 가능한 범위인 service, repository 계층에서 이루어진다.
+A: 개발자가 직접 트랜잭션의 경계 설정을 통해서 트랜잭션을 명시하는 일이 필요하다. 트랜잭션의 경계는 프레젠테이션층과 비지니스 로직 층 사이에 존재하는 것이 일반적으로 서비스층에서 트랜잭션을 시작한다. 스프링은 트랜잭션 추상화 인터페이스인 PlatformTransactionManager를 제공하여 다양한 데이터소스에 따라서 트랜잭션을 관리할 수 있도록 하는데 이는 getTransaction, rollback, commit으로 구성되어있다. getTransaction 파라미터로 전달되는 Transaction Definition에 따라 트랜잭션 시작하고 문제없이 이루어지면 commit, 문제발생 시 rollback을 호출한다. (getTransacton 부터 commit 혹은 rollback이 이루어지는 범위 까지가 트랜잭션의 경계설정이다)
Q: 스프링에서의 트랜잭션은 어떻게 이루어지는가 ?
A: @Transactional 어노테이션을 활용하여 트랜잭션을 사용할 수 있고 readOnly=true 옵션을 사용시 변경감지 스냅샷을 보관하지 않기 때문에 성능을 개선할 수 있다.
+A: 직접 코드로 구현되는 방식으로는 스프링에서 제공하는 트랜잭션 매니저 구현체를 이용한다. 대표적으로 각각의 데이터를 독립적으로 사용하는(하나의 데이터베이스) 로컬 트랜잭션에 사용되는 DataSourceTransactionManager(JDBC), JpaTransactionManager(JPA)와 하나 이상의 데이터베이스를 사용하는 글로벌 트랜잭션에 사용되는 JtaTransactionManger(다른서버에 분산된 것도 묶을 수 있다)이 존재한다. 직접 코드로 구현되는 방식 외에도 스프링 AOP를 이용한 선언적 트랜잭션을 제공한다. 선언적 트랜잭션에는 빈설정파일에서 트랜잭션 매니저를 등록하고 속성과 대상을 정의해 트랜잭션을 적용하는 tx namespace 방법(일괄적으로 트랜잭션 적용하고 변경)과 어노테이션(메서드, 클래스, 인터페이스에 적용)을 기반으로 설정하는 방법이 있다. 어노테이션은 데이터베이스에 여러번 접근하면서 하나의 작업을 수행하는 서비스계층 메서드에 붙이는 것이 통상적이다. 또한 어노테이션 속성으로 트랜잭션 매니저를 지정이 가능한다. ( ex) @Transactional(transactionManager="txManager"))
Q: 그럼 repository에서도 @Transactional 어노테이션이 붙을 수 있나? @Transactional은 Controller에서도 붙을 수 있나?
A: 비지니스 로직이 이루어지는 서비스계층에서 해당 어노테이션을 사용한다.
+A: 기본적으로 JpaRepository가 제공하는 메서드에는 트랜잭션 처리가 되어있고 만들어 추가한 메서드의 경우 어노테이션을 사용할 수 있다. SpringMVC Controller에서는 @Transactional 어노테이션이 작동하지 않는데 그 이유는 SpringAOP의 경우 인터페이스를 활용한 다이나믹 프록시 기법으로 동작하기 때문에 인터페이스를 가지고 있지 않은 Controller의 경우 해당 어노테이션을 사용할 수 없다.
Q: 비지니스로직은 도메인에서 이루어지지 않나? 도메인에서 @Transactional을 활용할 수 있나?
A: 비지니스 로직을 사용하는 서비스 계층에서 해당 어노테이션을 사용합니다.
+A: (위의 이유로) 인터페이스를 가지고 있지 않은 클래스의 경우 해당 어노테이션을 사용할 수 없다. 또한 데이터베이스에 여러번 접근하면서 하나의 작업을 수행하는 서비스계층 메서드에 붙이는 것이 통상적이다.
(아마 다음 질문은 이리저리 헤매는 나를 위해서 AOP, 다이나믹 프록시로 유도해주신 것 같다)
Q: 그럼 @Transactional이 붙은 메소드에는 모두 작동 될 수 있는가?
A: private메서드나 final 메서드에서는 어노테이션이 직동하지 않는데 이는 스프링은 트랜잭션 처리를 위해 빈 객체에 타깃 클래스를 상속해서 프록시 객체를 생성하기 때문에 private메서드의 경우 상속이 불가능하여 @Transactional 어노테이션이 적용되지 않는다. 같은 이유로 final 메서드도 적용되지 않는다. 스프링 프록시는 프록시를 통해 들어온 외부 메서드의 호출에서만 가로챌 수 있기 때문에 내부 메서드의 @Transactional 어노테이션을 알 수 없다.
Q: Service레이어에서의 단위테스트 방법은 무엇이 있는가?
A: service 레이어는 controller, repository와 관계하고 있고 repository를 의존하고 있기 때문에 서비스 계층의 단위테스트를 위해서 의존관계를 끊어내기 위해 Mock 객체를 사용하여 테스트를 진행할 수 있다.
+A: service 레이어는 실제 db를 사용하게 되면서 사실상 통합 테스트가 되어버린다. 의존관계를 끊어내기 위해서 Mock 프레임워크 혹은 Fake 객체를 사용하여 테스트를 진행할 수 있다.
Q: Mock 객체 대신 Fake 객체는?
A: Mock 객체는 .thenReturn 으로 받아오는 객체의 상태 변화가 감지가 안된다는 단점이 있지만 Fake 객체는 구현하기가 어렵고, Fake Object에 대한 단위 테스트가 필요할 정도의 복잡성을 지닐 수 있어서 Mock 객체를 사용한다.
+A: 상태기반의 테스트를 진행하고자 할 때는 Fake객체를 행위 기반의 테스트를 진행하고자 할 때는 Mock 객체를 이용한 테스트를 진행할 수 있다.
Q: 필요한 부분만 구현하여 Fake 객체를 사용하면 되지 않는가?
A: Mock 객체를 사용함으로서 Fake 객체 구현보다 service의 단위 테스트에 집중할 수 있다.
+A: 테스트 환경 구축에 너무 많은 시간이 소요되거나 환경 모듈 구축이 어려운 경우, 아직 실제 객체가 없는 경우에 Mock을 사용할 수 있다.
Q: 인수테스트란 무엇인가?
A: 시스템이 예상대로 동작하는지 확인하는 테스트다. 사용자 요구사항을 만족하는지에 대해서 이루어지는 테스트다.
+A: 소프트웨어가 사용자 요구사항을 만족하는지에 맞춰 작성된 테스트로 내부 구현이나 기술에 의존적이지 않은 블랙박스 테스트다. 인수테스트 주도개발은 인수조건-> 시나리오로 표현된 인수테스트 작성 -> 문서화 -> 수현 및 단위테스트 -> API 개발 -> 테스트 리팩토링의 순서로 이루어지며 표면적 요소로 검사가 이루어진다. 이러한 개발은 TDD의 단점을 보완하고 요구사항을 사전에 정의하고 검증하여 명확하게 필요기능을 구현할 수 있다. 빠른 피드백을 받을 수 있으며 기존 기능을 망가뜨리지 않고 새기능을 구현할 수 있다.
Q: 예상대로 동작하는지 확인한다면 단위테스트와 차이가 무엇인가?
A: 사용자 요구사항을 만족하는지에 대해서 이루어지는 테스트다.
+A: 비지니스에 초점을 두어 사용자 스토리에 맞춰 진행된다는 것이 다른 점이다. 다른 의사소통 집단으로부터 시나리오(필요 요소, 구현 결과)를 인수 받아 개발한다. 시나리오에서 요구하는 것은 누가, 어떤 목적으로, 무엇을 하는 가 이며 이러한 기능은 주로 API를 통해서 드러나 인수테스트는 주로 이 API를 확인하는 방식으로 이루어진다. 소프트웨어 인수를 위해 이루어지는 테스트로 인수조건대로 작동하는지 검증이 필요하다.
Q: 인수테스트와 API 테스트와의 차이가 무엇인가?
A: ...
(이 질문은 추후에 멘토님에게 여쭤보아 추가 답변을 받았다)
+A: API테스트는 시스템이나 컴포넌트간의 메세지나 데이터 전송에 대한 테스트를 수행하며 GUI를 배제하고 클라이언트-서버간에 이루어진다. (mid-level-testing) 인수테스트는 실제 개발환경과 유사하게 테스트 환경을 구성하고 given-when-then 형식으로 주어진 사용자 스토리를 만족하였는지 중점으로 테스트를 진행하며 API 레벨에서 인수테스트가 작성되는 것이다. 따라서 단순히 API를 목적을 위해서 API를 작성하고 status를 검사하는 것이 아니라 사용자 요구사항 시나리오에 초점을 맞추고 이를 만족하는 지를 검사하는 것이 목적 이다. 인수테스트는 사용자 시나리오 만족과 API로 결과를 확인하는 부분을 지니고 있는데 여기서 RestAssured로 결과를 확인하는 부분이 API 테스트 진행 파트를 담당한다고 볼 수 있다. API 테스트와 인수테스트는 결국 어느 것에 초점을 두고 테스트를 진행하느냐에 따라서 차이가 발생한다고 볼 수 있다.
🌱 모의 면접 후기
모의면접은 처음인데 정말 😣... 엉망진창 와진창 ⚡️ 블로그를 작성할 때 공부를 깊게 해야겠다. 아는게 없으면 질문도 이해 못한다. 스프링 다시 공부해야겠다. 그동안 뭘 한건지 증말~
( 재공부 하면서 참고한 자료 )
https://www.youtube.com/watch?v=ITVpmjM4mUE&t=4s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
https://www.youtube.com/watch?v=OM_bN4wzd0g&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
https://www.youtube.com/watch?v=aX9c7z9l_u8&t=22s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
https://brainbackdoor.tistory.com/142
'학습로그' 카테고리의 다른 글
월간 멘토링 - 4개월차 (0) 2022.04.28 월간 멘토링 - 3개월차 (0) 2022.04.28 월간 멘토링 - 2개월차 (0) 2022.02.28 월간 멘토링 - 1개월차 (0) 2022.02.28 프로젝트 공방 멘토링 (Feat. NextStep) (0) 2022.02.28