- 클래스의 복잡도가 올라가면 클래스를 분리하고 메서드의 크기를 줄여 유지보수, 테스트 하기 좋은 코드로 개선
- 실무와 비슷한 환경의 레거시 코드를 TDD, 클린코드를 적용하여 구조 개선
- 데이터가 이미 존재하는 상태에서 요구사항 변경 시 리팩토링 방안
- DB 테이블보다 먼저 도메인 관점에서의 설계 및 개발
- 의존의 가장 마지막 단계에 있는 기능에서 시작하는 테스트
- public 메서드를 제공할 때, 사용자가 메서드 호출 순서를 몰라도 사용함에 오류가 없도록 설계
- 학습 관리 시스템의 수강신청 요구사항을 파악한다.
- 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다.
- 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다.
- 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다.
- 질문 데이터의 삭제 상태를 변경한다. (deleted = true)
- 로그인 사용자 == 질문글 작성자인 경우 삭제 가능
- 질문글에 답변글이 없는 경우 삭제 가능
- 질문을 삭제하면 답변 또한 삭제한다.
- 답변의 삭제 상태를 변경한다. (deleted = true)
- 답변글 작성자 != 로그인 사용자인 경우 답변글을 삭제할 수 없다.
- 질문글 작성자 != 답변글 작성자인 경우 답변글을 삭제할 수 없다.
- QnaService의 deleteQuestion() 메서드의 핵심 비지니스 로직을 도메인 모델 객체에 구현
- TDD로 구현
- 리팩토링 후에도 QnaServiceTest의 모든 테스트는 통과해야 한다.
- 답변을 삭제한다. (deleted = true)
- 질문을 삭제한다. (deleted = true)
- 답변과 질문의 삭제 이력을 가져온다.
- Wrapper 클래스에서 변수명은 values, value, 값을 가져오는 메서드명은 value(), get()으로 사용해 보기
- delete 작업 후에 deleteHistories를 즉시 반환하도록 변경
- Answer의 delete()가 답변만 삭제하고 싶을 경우에도 대응할 수 있도록 변경
- 과정(Course)은 기수 단위로 운영되며, 여러개의 강의(Session)을 가질 수 있다.
- 강의(Session)
- 시작일과 종료일을 가진다.
- 강의 커버 이미지를 가진다.
- 이미지 크기는 1MB 이하이다.
- 이미지 타입은 gif, jpg(jpeg 포함), png, svg만 허용한다.
- 이미지의 width는 300픽셀, height는 200픽셀 이상이어야 하며, width와 height의 비율은 3:2여야 한다.
- 무료강의와 유료강의로 나뉜다.
- 무료 강의는 최대 수강 인원의 제한이 없다.
- 유료 강의는 최대 수강 인원을 초과할 수 없다.
- 유료 강의는 수강생이 결제한 금액과 수강료가 일치할 때 수강 신청이 가능하다.
- 유료 강의의 경우 결제는 이미 완료한 것으로 가정하고 이후 과정을 구현한다.
- 결제를 완료한 결제 정보는 payments 모듈을 통해 관리되며, 결제 정보는 Payment 객체에 담겨 반한된다.
- 준비중, 모집중, 종료 3가지 상태를 가진다.
- 수강신청
- 로그인 유저는 강의를 대상으로 수강신청을 할 수 있다.
- 수강신청은 모집중 상태인 경우에만 가능하다.
- DB 테이블 설계 없이 도메인 모델부터 구현한다.
- 도메인 모델은 TDD로 구현한다. 단, Service 클래스는 단위 테스트가 없어도 된다.
- 이미지 타입을 관리할 수 있는 enum을 사용해보기
- 항상 인자가 필요한 경우 기본 생성자를 삭제하기
- 이미지 가로, 세로 비율을 구할 때 부동소수점인 Double 외에 곱셈 혹은 BigDecimal을 사용해보기
- 코드 가독성과 속도를 고려하여 BigDecimal이 아닌 곱셈으로 수정
- 강의의 기간을 관리하는 클래스를 만들어서 유효성 검사를 진행해보기
- 강의에 필수 값이 있다면 생성 시 검증을 진행해보기
- 클래스 네임에 Info, Data는 사용하지 않고, 의미를 보다 명확히 하기
- 수강 신청이 완료되면 수강 인원이 늘어야 할 것
- 파일 마지막의 newLine에 대해 공부해 보고, 누락된 부분을 추가하기
- userNumber를 가져오는 방식에 대한 고민
- 값이 필요한 객체의 경우 기본생성자를 제공하지 않고, 추가적인 validate를 진행
- 2단계에서 구현한 도메인 모델을 DB 테이블과 매핑하고, 데이터를 저장한다.
- schema.sql 에 DB 테이블 추가
- Session
- CoverImage
- NsUserSession
- CRUD 코드 추가
- sessionRepository
- coverImageRepository
- CRUD 코드에 대한 테스트 코드 추가
- sessionRepository
- schema.sql 에 DB 테이블 추가
- CoverImage와 Sesssion의 관계 고민
- Session은 CoverImage를 가진다.
- 수강신청 시 CoverImage의 정보는 필요하지 않다.
- CoverImage는 sessionId를 반드시 안다.
- Repository 와 DAO의 차이를 알아보고 설계를 수정
- 현재의 설계는 DAO에 가깝다. Repository는 DAO를 이용해서 서비스단에서 사용하고자 하는 객체를 만드는데 집중한다.
- CoverImage의 중복된 validation 제거
- Wrapper 타입과 Primitive 타입의 쓰임새 확인 후 수정
- SessionPaymentCondition 내 메서드의 적합한 명명 고민
- 수강신청 로직 수정(검증)
- 객체 저장 후 id값을 반환하도록 하기
- Class 레벨의 @Transactional 활용
- (기존) 강의가 모집중일 때만 수강 신청이 가능하다.
- (변경) 강의가 진행 중인 상태에서도 수강신청이 가능하다.
- 강의 진행 상태 (준비중, 진행중, 종료)와 모집 상태(모집중, 비모집중)으로 분리한다.
- 강의가 '진행중, 준비중'이고 '모집중'인 상태에서만 수강신청이 가능하다.
- (변경) 강의가 진행 중인 상태에서도 수강신청이 가능하다.
- (기존) 강의는 강의 커버 이미지를 가진다.
- (변경) 강의는 하나 이상의 강의 커버 이미지를 가질 수 있다.
- (기존) 수강 신청은 별도의 승인이 필요 없다.
- (변경) '선발된' 인원만 수강이 가능해야 한다.
- 강사는 수강신청한 사람 중 선발된 인원에 대해서만 수강 승인이 가능해야 한다.
- 강사는 수강신청한 사람 중 선발되지 않은 사람은 수강을 취소할 수 있어야 한다.
- 수강 인원은 미리 정해져있다.
- 수강신청은 아무나 가능하지만, 강사는 선발된 인원을 확인해서 수강 승인 혹은 취소를 진행한다.
- DB상에 이미 데이터가 있다는 전제 하에 진행한다. (기존에 쌓인 데이터를 지우지 않아야 한다.)
- Session 컬럼 session_status를 session_recruitment_status로 변경, session_progress_status 추가
- CoverImage에 id pk로 추가
- NsUserSession에 registered 필드 추가, 기존 인원은 ture로 업데이트 하는 시나리오
- create table DDL문을 수정하지 않고 Alter table 을 이용해본다.
- session
- ns_user_session
- sessionStatus를 분류하되, 기존 데이터의로도 수강 신청이 가능하도록 구현
- 강의 진행 컬럼을 추가하되, 해당 값이 존재하지 않는 기존 강의의 경우 EMPTY 값을 갖도록 함
- 수강 신청 기능과 강사의 신청 승인은 각각의 기능으로 구현된다.
- NsUserSession이 3가지 상태(신청, 승인, 취소)를 갖도록 구현해본다.
- 수강 승인 기능이 생긴 시점을 기준으로 수강 승인 기능을 구현한다.
- session 테이블에 approval_required 컬럼 추가, default value false
- ns_user_session 테이블에 enrollment_status 컬럼 추가, default value 'APPROVED'
- Session에 강사 정보를 추가 및 검증한다.
- 수강 승인을 할 수 있는 인원이 최대 수강 인원으로 제한되도록 해본다.
- 추가로, 수강 인원만큼 승인이 되었다면 추가로 수강 승인이 되지 않도록 제한한다.
- NsUserSession 과 같은 클래스 네임은 개발자의 관점으로, 도메인 입장에서 더욱 적합한 이름을 고민해야 함
- Student, Students
- enum에게도 역할을 위임할 수 있다. 단, 작은 메서드일 경우 과하게 느껴질 수 있음
- 수강 승인/취소 역할을 NsUserSession이 담당하도록 해본다
- 값을 변경할 수 없는 필드에 대해서는 final을 선언하는 습관을 들인다
- NsUserSessions(Students) 에 새로운 수강자를 추가한 뒤 id 혹은 이름으로 찾는 메서드의 필요성
- Session 클래스의 필드 수가 많아지며 복잡도는 증가한다. 클래스 분리를 해 볼 것
- Enrollment 클래스를 추가하고 enroll에 대한 테스트 분리
- 현재 수강중인 인원 수를 찾기 위해 매번 수강생 전체 리스트를 갖고 오는 것은 성능상 이슈가 생길 수 있다.
- session 테이블 역정규화, 수강 인원 직접 관리