Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

도메인 객체를 POJO로 전환 완료 #403

Merged
merged 78 commits into from
Jul 19, 2024
Merged

도메인 객체를 POJO로 전환 완료 #403

merged 78 commits into from
Jul 19, 2024

Conversation

limehee
Copy link
Collaborator

@limehee limehee commented Jul 11, 2024

Summary

#401

도메인 객체를 POJO(Plain Old Java Object)로 전환하여 JPA 엔티티와 분리하는 작업을 수행했습니다. 이 작업은 도메인 객체와 영속성 로직을 명확히 분리하여 각자의 책임을 분리하고, 코드의 유연성과 유지보수성을 향상시키기 위함입니다.

Tasks

  • 도메인 객체를 POJO로 전환하여 비즈니스 로직과 영속성 로직을 분리
  • 기존 JPA 엔티티에서 비즈니스 로직을 분리하여 순수한 POJO 클래스로 작성
  • POJO 클래스에서 JPA와 같은 영속성 관련 어노테이션 제거
  • JPA 엔티티를 별도의 클래스로 작성하여 데이터베이스 테이블과의 매핑만 담당
  • 도메인 객체와 JPA 엔티티 간의 변환을 담당하는 매퍼(Mapper) 클래스 작성
  • 서비스 계층에서 도메인 객체를 사용하여 비즈니스 로직 처리 및 데이터베이스 연동 시 JPA 엔티티로 변환하여 저장 및 조회
  • 도메인 객체의 상태 변화 시 도메인 이벤트 발행
  • 이벤트 핸들러를 통해 다른 도메인 모델에 변경 사항 전달 및 후속 조치 수행
  • 트랜잭션 관리를 통해 데이터의 일관성과 원자성 보장
  • 다른 도메인을 참조할 때 external 패키지의 클래스를 참조하도록 작업

패키지 구조

domain
├── adapter
│   ├── in.web
│   │   ├── 유스케이스별 컨트롤러가 포함됩니다. 각 컨트롤러는 특정 유스케이스를 처리하는 엔드포인트를 제공합니다.
│   └── out.persistence
│       ├── 영속성을 관리하는 어댑터들이 위치합니다. JPA 엔티티, 매퍼, 리포지토리 등이 포함됩니다.
├── application
│   ├── dto
│   │   ├── 요청과 응답을 처리하는 DTO 클래스들이 위치합니다.
│   ├── event
│   │   ├── 도메인 이벤트와 관련된 클래스들이 위치합니다.
│   ├── port
│   │   ├── 인바운드 및 아웃바운드 포트 인터페이스를 정의합니다. 애플리케이션 외부에서 들어오는 요청을 처리하고, 외부 시스템이나 데이터베이스로의 요청을 처리하는 역할을 합니다.
│   └── service
│       ├── 인바운드 포트 인터페이스를 구현하는 서비스 클래스들이 위치합니다. 비즈니스 로직을 구현하고, 필요한 경우 아웃바운드 포트를 호출합니다.
└── domain
    ├── 도메인 모델이 위치합니다. 애플리케이션의 핵심 비즈니스 로직과 규칙을 정의합니다.

external
├── category
│   ├── domain
│   │   ├── application
│   │   │   ├── port
│   │   │   │   ├── 다른 도메인에서 사용할 수 있는 인바운드 포트 인터페이스를 정의합니다.
│   │   │   └── service
│   │   │       ├── 인바운드 포트 인터페이스를 구현하는 서비스 클래스들이 위치합니다.

외부에서의 불필요한 접근을 방지하고 모듈 간의 결합도를 낮추기 위해 package-private 구조로 작성되었습니다.

ETC

  • 도메인을 서비스에 따라 상위 패키지로 재분류했습니다.
  • 기능을 보다 명확하게 표현하기 위해 LoginAttemptLog 테이블명을 AccountAccessLog로 변경했습니다.
  • 유효성을 명시적으로 검사하는 ValidationService를 제거했습니다.
  • API 문서에서 Tag를 서비스에 따라 재분류했습니다.
  • BaseEntity가 isDeleted를 포함하지 않도록 변경했습니다.
  • Controller에서 영속성 객체를 참조하지 않도록 변경했습니다.
  • 응답 DTO를 정렬 기준으로 사용하도록 변경했습니다.
  • 다음의 테이블에서 외래키가 제거되었습니다.
    • 제거된 Member 참조: Absent, ActivityGroupBoard, ApplyForm, Attendance, GroupMember, Review, Schedule, UploadedFile
    • 제거된 Book 참조: BookLoanRecord
    • 제거된 Board 참조: Comment

Query

외래키 제거

  • 외래키 제약 조건 확인
-- Member 테이블을 참조하는 외래키 제약 조건 확인
SELECT
    conname,
    conrelid::regclass AS tablename,
    confrelid::regclass AS reftable,
    a.attname AS column_name
FROM
    pg_constraint AS c
    JOIN pg_attribute AS a ON a.attnum = ANY(c.conkey) AND a.attrelid = c.conrelid
WHERE
    c.contype = 'f'
    AND c.confrelid::regclass = 'public.member'::regclass;

-- Book 테이블을 참조하는 외래키 제약 조건 확인
SELECT
    conname,
    conrelid::regclass AS tablename,
    confrelid::regclass AS reftable,
    a.attname AS column_name
FROM
    pg_constraint AS c
    JOIN pg_attribute AS a ON a.attnum = ANY(c.conkey) AND a.attrelid = c.conrelid
WHERE
    c.contype = 'f'
    AND c.confrelid::regclass = 'public.book'::regclass;

-- Board 테이블을 참조하는 외래키 제약 조건 확인
SELECT
    conname,
    conrelid::regclass AS tablename,
    confrelid::regclass AS reftable,
    a.attname AS column_name
FROM
    pg_constraint AS c
    JOIN pg_attribute AS a ON a.attnum = ANY(c.conkey) AND a.attrelid = c.conrelid
WHERE
    c.contype = 'f'
    AND c.confrelid::regclass = 'public.board'::regclass;
  • 외래키 제약 조건 삭제
DO $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN (
        SELECT conname, conrelid::regclass AS tablename, a.attname AS column_name
        FROM pg_constraint AS c
        JOIN pg_attribute AS a ON a.attnum = ANY(c.conkey) AND a.attrelid = c.conrelid
        WHERE c.contype = 'f'
          AND (c.confrelid::regclass = 'public.member'::regclass OR 
               c.confrelid::regclass = 'public.book'::regclass OR
               c.confrelid::regclass = 'public.board'::regclass)
    ) LOOP
        EXECUTE 'ALTER TABLE ' || r.tablename || ' DROP CONSTRAINT ' || r.conname;
    END LOOP;
END $$;

login_attempt_log -> account_access_log 변경된 테이블 반영

-- 1. 기존 테이블 이름 변경
ALTER TABLE login_attempt_log RENAME TO old_login_attempt_log;

-- 2. 새로운 테이블 생성
CREATE TABLE account_access_log
(
    id                    bigserial PRIMARY KEY,
    created_at            timestamp(6),
    updated_at            timestamp(6),
    account_access_result varchar(255)
        CONSTRAINT account_access_log_account_access_result_check
            CHECK ((account_access_result)::text = ANY
                   ((ARRAY ['TOTP'::character varying, 'SUCCESS'::character varying, 'FAILURE'::character varying])::text[])),
    ip_address            varchar(255),
    location              varchar(255),
    member_id             varchar(255) NOT NULL,
    user_agent            varchar(255),
    access_time           timestamp(6)
);

-- 3. 데이터 이동
INSERT INTO account_access_log (id, created_at, updated_at, account_access_result, ip_address, location, member_id, user_agent, access_time)
SELECT id, created_at, updated_at, login_attempt_result::varchar(255), ip_address, location, member_id, user_agent, login_attempt_time
FROM old_login_attempt_log;

-- 4. 기존 테이블 삭제
DROP TABLE old_login_attempt_log;

Screenshot

image
image

limehee added 30 commits July 10, 2024 03:13
@limehee
Copy link
Collaborator Author

limehee commented Jul 17, 2024

MapStruct 적용 범위

  • 도메인 객체와 영속성 객체 간의 매핑

그 외 매핑은 유지

  • Comment 객체의 경우, 로직이 복잡하고 MapStruct로 변경했을 때 기존처럼 계층형 구조로 응답이 생성되지 않는 문제가 발생했습니다.
  • 도메인 객체와 DTO 간의 매핑은 변환할 때 여러 개의 파라미터를 받는 경우가 많아 오히려 복잡도를 더 키우는 느낌이 들었습니다.

그럼에도 불구하고, 필요하다고 여겨지면 도메인 객체와 DTO 간의 매핑 작업을 MapStruct로 변경하겠습니다.

@mingmingmon
Copy link
Collaborator

MapStruct 적용 범위

  • 도메인 객체와 영속성 객체 간의 매핑

그 외 매핑은 유지

  • Comment 객체의 경우, 로직이 복잡하고 MapStruct로 변경했을 때 기존처럼 계층형 구조로 응답이 생성되지 않는 문제가 발생했습니다.
  • 도메인 객체와 DTO 간의 매핑은 변환할 때 여러 개의 파라미터를 받는 경우가 많아 오히려 복잡도를 더 키우는 느낌이 들었습니다.

그럼에도 불구하고, 필요하다고 여겨지면 도메인 객체와 DTO 간의 매핑 작업을 MapStruct로 변경하겠습니다.

제가 말씀드린 방향과 일치하게 리팩토링해주셨네요!
그 외 매핑을 유지하는 부분에서도 충분히 이해되는 내용입니다.
제 피드백을 오히려 발전시키고 수용까지 해주셔서 감사합니다!

limehee added 22 commits July 18, 2024 14:24
@limehee limehee merged commit 6de7777 into develop Jul 19, 2024
1 check passed
@limehee limehee deleted the refactor/#401 branch July 19, 2024 05:21
@limehee limehee mentioned this pull request Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨 Refactor 코드 수정 및 개선
Projects
None yet
Development

Successfully merging this pull request may close these issues.

도메인 객체를 POJO로 전환
3 participants