🔶Layered Architecture
🔶동시성 테스트
🔶Git
≣ 목차
Layered Architecture
presentation layer -> domain layer -> infra layer
문제점: domain layer에서 DTO를 Mapper를 통해 타입을 변경할 수 없다. presentation layer에서만 적용 가능함.
DIP를 적용할 경우 domain layer에서 infra에 접근할 수 있다: domain layer <- infra layer
- presentation layer
- Controller, Request, Response
- interface http api protocol
Request, Response
프로토콜 네이밍 규약에 따른 네이밍 지정
UserDTO.Request, UserDTO.Response 처럼 지정할 경우 가독성 Good~
- domain(application) layer
- Service, UserRepository(interface), User
- DIP를 적용해서 Repository가 infra layer에서 올라오도록 한다.
- infra layer
- UserRepositoryImpl, UserEntity(jpa)
class UserService {
User getUser() {
User user = userRepository.findById();
return user;
//UserEntity userEntity = userRepository.findById();
//return UserMapper.toDomain(userEntity);
}
}
interface UserRepository {
User findByID();
}
class UserRepositoryImpl implements UserRepository {
//생성자를 통해 구현체를 가져와서 사용할 수 있다.
UserJpaRepository jpaRepo;
UserRepositoryImpl(UserJpaRepository jpaRepo) {
this.jpaRepo = jpaRepo;
}
@Override
User findById() {
UserEntity userEntity = jpaRepo.findById();
//User user = User.of(userEntity); //주의* DIP 위반
//return UserEntitMapper.toDomain(userEntity);
User user = UserEntity.toUser(userEntity);
return user;
}
}
QNA
[기존 계층 흐름도]
UserController -> UserService -> UserRepository
[DIP 적용]
UserController -> UserService - UserRepository(interface) <- UserRepositoryImpl - UserEntity
0. DIP 적용하면 (클린 아키텍처 + 레이어드 아키텍처) 인가요?
-> 정확히는 아님 나중에 추가적 설명
1. UserRepository interface를 UserService와 함께 domain 계층에 둔다.
2. UserRepositoryImpl은 UserRepository의 구현체이다. (method overriding 진행)
2-1. 생성자를 통해 주입 받을 구체적인 Repository를 지정한다 (예시: jpa, querydsl)
-> UserJpaRepository interface 선언
3. UserEntity -> User 변환 작업이 필요할 경우 UserRepositoryImpl에서 진행한다.
-> DIP 하고나서 양방향 참조가 생기지 않기 위해 진행 (꼬이지 않으려면)
3-1. 주의* UserRepositoryImpl에서 변환 작업 시, User 객체에서 직접 메서드를 호출해서 변환하면 안된다.(DIP 위반)
-> import 되기 때문에 (참조 발생)
3-2. UserEntity의 메서드나 Mapper 클래스를 통해 User 객체로 변환한다.
-> of로 하는 게 더 일반적이긴 함 (취향 차이~!)
3-3. 질문: Mapper 클래스도 infra 계층에 두는 것이 맞나요?
-> 각각 변환이 필요해서 infra controller에 각각 mapper가 필요함. 양쪽에서 변환해주기 때문에 도메인은 mapper 필요없음
테스트
- controller E2E 테스트
- mockMVC 사용
- service 단위 테스트 -> repository stub/mock
- service 통합 테스트 -> impl 물려서 테스트
- repository 단위 테스트 X
Stub vs Mock
- stub: 구현체 필요
- mock: 재사용 불가
동시성 테스트
동시에 요청이 들어온 걸 정합성을 지키면서 처리한다.
동일한 요청자가 여러 번 시도하거나, 공유 자원에 대해서 동시성이 발생할 경우 문제가 발생한다.
userA: a 요청
userB: b 요청
주의* 네트워크 스펙(라우팅 등)이 다르기 때문에 동시에 요청하더라도 어떤 요청이 수행될지 알 수 없음
TCP는 데이터를 순차적으로 전송한다.
- Lock
- Lock을 오래 기다리는 요청 스레드가 많아질 경우 메모리에 문제가 생긴다.
- ReetrantLock (ex. id 별 Lock 지정)
- 메모리
- ConcurrentHashMap (순차적 보장 해시맵)
- CountDownLanch.await()
- CompletableFuture.allOf({병렬로 수행할 함수 집합}).join()
- 병렬로 스레드 열에서 작업시킬 수 있다.
- synchronized atomic
- mutex
- valitile
- semaphore
- CyclicBarrier
- StampedLock
- 등등등.......................
Addition
Timestamp -> Queueing
셀레니움
시나리오 테스트
DTO - Mapper 클래스, of, from 메서드
샤딩? 분산?
Git
git switch -c branch
현재 있는 브랜치 기반으로 새로운 브랜치 생성
'Blog > Education' 카테고리의 다른 글
2주차 QNA & 멘토링 (0) | 2024.06.28 |
---|---|
2주차 발제 정리 (0) | 2024.06.22 |
99클럽 코테 스터디 46일차 TIL + DP (0) | 2024.05.09 |
99클럽 코테 스터디 45일차 TIL + DP (0) | 2024.05.08 |
99클럽 코테 스터디 44일차 TIL + DFS + 브루트포스 (0) | 2024.05.07 |
댓글