오늘의 키워드
- 피드백을 기반으로 리펙토링
- https://github.com/marlboro09/schedule/wiki
오늘의 내용
- Servcie레이어를 하나의 패키지로 모아두셨는데 JwtService는 따로 빠져있습니다. 패키지 룰에 맞게 위치시켜 주세요. JWT는 도메인 패키지로 묶이고 타 서비스들은 서비스 패키지입니다. 하나로 통일시켜 주세요
- 아래와 같이 수정완
- JwtService 파일을 service패키지로 이동해서 해결함
- 아래와 같이 수정완
- service마다 transactional 고민한 것 좋습니다. 다만 너무 많이 사용하게 되면 낭비니 필요한 부분에서만 사용해 주세요 (지금은 큰 상관없습니다. 추후 프로젝트가 커지고 여러 서비스레이어가 복잡하게 엮기게 되면 그때 고민하시면 됩니다)
- @transactional은 여러 작업을 하나의 논리적 단위로 묶어 일관된 상태를 유지시켜서 다중 사용자가 동시에 데이터베이스를 접근할 때 생기는 동시성 제어 문제는 해결하는 데 사용된다. 또한 @Transactional 어노테이션을 사용하면 해당 메서드가 호출될 때 트랜잭션이 시작되고, 메소드가 정상적으로 완료되면 트랜잭션이 커밋되는데 만약 예외가 발생하면 트랜잭션이 롤백되어 시스템 오류 발생 시 데이터베이스를 이전 일관된 상태로 복구가 가능해진다.
- 트랜잭션 관리의 일관성 유지를 위해 서비스 계층에서 명시적으로 관리하는 것이 좋지만 현재 코드에서는 단일 데이터의 조작 작업만 수행되고 있어 트랜잭션 애너테이션을 제거했다.
- 코드가 더 확장되거나 다른 데이터 조작 작업이 추가될 경우 다시 추가예정이다.
- 삭제를 해도 정상작동을 해서 괜찮을 줄 알았으나 영속성 콘텍스트를 적용시키면서 데이터베이스가 수정되지 않는 오류가 발생해 'ScheduleService'에 @transactional을 다시 추가했다.
- @Transactional을 사용함으로써 JPA는 자동으로 영속성 컨텍스트를 생성하고 끝날 때까지 이를 유지시킨다. 트랜잭션이 끝나면 영속성 콘텍스트의 변경사항이 DB에 반영된다.
- 트랜잭션 관리의 일관성 유지를 위해 서비스 계층에서 명시적으로 관리하는 것이 좋지만 현재 코드에서는 단일 데이터의 조작 작업만 수행되고 있어 트랜잭션 애너테이션을 제거했다.
- @transactional은 여러 작업을 하나의 논리적 단위로 묶어 일관된 상태를 유지시켜서 다중 사용자가 동시에 데이터베이스를 접근할 때 생기는 동시성 제어 문제는 해결하는 데 사용된다. 또한 @Transactional 어노테이션을 사용하면 해당 메서드가 호출될 때 트랜잭션이 시작되고, 메소드가 정상적으로 완료되면 트랜잭션이 커밋되는데 만약 예외가 발생하면 트랜잭션이 롤백되어 시스템 오류 발생 시 데이터베이스를 이전 일관된 상태로 복구가 가능해진다.
- UserDetails에서 가지고 온 user는 영속성 콘텍스트에 존재하지 않습니다. 지금은 버그가 발생하지 않았지만 추후 발생할 여지가 크니 알고 계시면 좋겠습니다. (연관관계 조회 및 생성 시 에러가 많이 발생합니다.)
- 영속성 콘텍스트를 이해하기 전에 Entity를 먼저 이해할 필요가 있었다.
- Entity는 JPA에서 데이터베이스 테이블과 매핑되는 자바 객체를 의미하는데 쉽게 말하면 DB의 레코드를 가바 객체로 다루기 위해 사용된다.
- 결국 이를 관리하는 게 영속성 콘텍스트이다.
- 영속성 콘텍스트는 Entity의 상태를 추적하고 변경 사항을 DB에 반영시켜 준다.
- 영속성 콘텍스트는 1차 캐시 역할을 해 동일한 트랜잭션 내에서 조회한 Entity를 캐시에 저장하고 재사용해 DB의 조회 횟수를 줄이고 성능을 향상해준다.
- 동일한 영속성 콘텍스트 내에서는 동일한 Entity 객체를 보장해 주는데 쉽게 말하면 동일한 Entity를 여러 번 조회해도 동일한 인스턴스가 반환된다.
- ! 문법을 잘 사용하십니다. 코드상에서는 전혀 문제가 없지만 가독성 측면으로 봤을 때는 휴먼 에러를 아주 많이 발생시키는 요인입니다. 어쩔 수 없이! 문법을 사용한다고 하면 Boolean notEqualByUser()와 같이 Boolean 함수를 만들어서 사용해 주세요. Entity에 method로 사용해도 되고 Service Layer function으로 만들어도 됩니다.
- 부정 연산자를 사용하는 것은 간결하고 직관적이지만 가독성과 유지보수 측면에서는 문제가 발생할 수 있었다.
- 코드의 의미를 반전시켜 복잡한 조건문일수록 코드의 이해가 쉽지 않게 한다.
'if (! user.isAdmin()) {
// 사용자 권한이 관리자 아닐 때의 처리
}'
위 코드는 단순한 조건문이지만, 조건이 더 추가되면 아래처럼 복잡해진다.
'if (!user.isAdmin() && !user.equals(schedule.getUser())) {
// 관리자도 아니고 일정의 사용자도 아닐 때의 처리
}' - 함수를 사용하면 작성자의 의도를 명확히 이해시킬 수 있다. 또한 함수로 조건을 분리하면 재사용성이 증가하는데 이로써 중복 코드를 줄이고 유지보수를 쉽게 할 수 있다.
'private boolean isNotAuthorizedUser(User user, Schedule schedule) {
return !user.isAdmin() && !user.equals(schedule.getUser());
}'
- CommentServcie에서 CommentRepository, ScheduleRepository를 모두 사용하셨습니다. 서비스 레이어는 모든 비즈니스 로직을 가지고 있기 때문에 Repository를 바로 사용하는 것이 아닌 Servcie를 통해서 사용해 주세요 그래야 Entity에 관한 룰이 지켜집니다.
- 이 피드백을 리펙토링 하기 위해서 서비스 레이어의 역할과 책임을 알 필요가 있었다.
- 서비스 레이어는 비즈니스 로직을 캡슐화하고 응용 프로그램의 핵심 동작을 처리하는 계층이다
- 비즈니스 로직의 캡슐화, 트랜잭션의 관리, 데이터 접근 조정, 유효성 검사를 한다.
- 직접적인 'Repository'사용을 피하는 이유
- 단일 책임 원칙 : 서비스 레이어는 비즈니스 로직을 처리하는데 집중해야 한다.
- 재사용성 : 서비스 레이어를 통해 레포지토리에 접근하면 비즈니스 로직을 다른 서비스에서도 재사용할 수 있다.
- 유지 보수성 : 비즈니스 로직과 데이터 접근 로직이 분리되어 있으며 각각을 독립적으로 수정하고 테스트가 가능해 유지 보수가 용이해진다.
- 일관성 : 모든 데이터 접근이 서비스 레이어를 통해 이루어져 비즈니스 규칙과 데이터 무결성을 일관되게 적용할 수 있다.
오늘의 회고
- 프로젝트 피드백이 들어와서 최대한 피드백을 반영해 리펙토링을 진행해 보았는데 맞게 했는지 잘 모르겠다. 내일부터는 팀프로젝트 시작인데 1인분은 할 수 있을까.....
'TIL' 카테고리의 다른 글
내일배움캠프 8주차 Spring Swagger 적용하기 (0) | 2024.06.06 |
---|---|
내일배움캠프 8주차 Java Class, 예외처리 (0) | 2024.06.04 |
내일배움캠프 7주차 Spring Refresh Token (0) | 2024.05.31 |
내일배움캠프 7주차 Spring Password Encoder, @Authenticationprincipal (0) | 2024.05.31 |
내일배움캠프 7주차 Spring @PathVariable, @RequestParam, @ModelAttribute, @RequestBody,...... (0) | 2024.05.29 |