놀았던 날이 없는데 논 것 처럼 블로그에 아무 것도 못써서 올리는 주간일지^_ㅠ
11/03(월)
- 오늘은 회사 모각코 사이드 프로젝트 대략적인 구성을 잡았다.
오프라인으로 모여서 했지만... 원활한 화면 공유를 위해 zep에서 진행하기

- front들은 core쪽 구상했고, 내가 속한 backend는 약간의 코드컨벤션이라거나 패키지 구조를 더 확실하게 잡았다.
root
├─ common # 공통(기술) 모듈: 유틸/웹/DB (도메인 규칙 금지)
│ ├─ utils # 순수 유틸(String/Time/Id 등)
│ ├─ exception # 글로벌 예외/에러응답/요청 로깅 등
│ └─ jpa # BaseEntity/Auditing/공통 Converter...
│
├─ gateway
│`
├─ core # 서비스 간 통신
│ ├─
│ └─ shared-kernel # ErrorCode, Result, 중립 값객체(웹/JPA 의존 금지)
│
├─ admin
│ └─ src/main/java/com/farm2pot/admin
│ ├─ product # 하위 도메인1
│ │ ├─ controller
│ │ │ └─ dto # ← Controller DTO(요청/응답)
│ │ │
│ │ ├─ service
│ │ │ └─ dto # ← Service DTO(Command/Query/Result: 내부용)
│ │ │
│ │ ├─ repository
│ │ │ └─ cutom # QueryDSL 구현
│ │ │
│ │ ├─ entity
│ │ └─ enums # 도메인 정책형 enum(표시 전용은 controller/dto 내부)
│ │
│ ├─ box # 하위 도메인2 (동일 규칙)
│ └─ policy # 하위 도메인3 (동일 규칙)
│
├─ subscription # 별도 마이크로서비스(동일 규칙)
│ └─ src/main/java/com/farm2pot/subscription/...
│
└─ user # 별도 마이크로서비스(동일 규칙)
└─ src/main/java/com/farm2pot/user/...
@ 최소규칙
- 레이어 의존 방향: controller → service → repository(interface) ← repository/impl
- DTO 분리
- controller/dto : 외부 계약(요청·응답). @Valid 등 프레임워크 애노테이션 허용.
- service/dto : 내부 유즈케이스 파라미터/결과. 프레임워크 의존 금지.
- DTO : record 사용
- DTO ↔ Entity 또는 DTO ↔ DTO간 변화는 MapStruct를 사용 ⇒ controller에서 책임을 질 예정이므로 controller\dto\mapper에 위치
- DTO 네이밍
- ProductResponse (단건 / 목록 ⇒ List<ProductResponse>)
- UpdateProductRequest (수정 요청)
- 요청 객체 (Service In):
- 예시: ProductCreateCommand, ProductUpdateCommand, ProductListQuery
- Service에게 어떤 행위(Command)를 수행하도록 명령하는 데이터라는 의미를 부여
- 응답 객체 (Service Out):
- 예시: ProductQueryResult, ProductCreateResult
- Service가 비즈니스 로직을 처리한 결과(Result) 데이터를 담고 있음을 나타냄
- Controller
- Enum 배치
- Repository
- 인터페이스는 repository 루트에, QueryDSL의 경우 repository/custom 분리.
- 서비스 간 호출
- 항상 gateway 경유(모듈 간 직접 참조 금지).
- 공통 모듈
- common: 서비스 호출 등 필요 없는 라이브러리성 모듈만(gradle에서 subProject에 dependecy 할 예정)
- 사이드 프로젝트 fork 떠서 로컬로 갖고오고, commit하는 방법까지 안내했다.
@ 개인으로 Fork따서 원격 연결하기
현재 원격 저장소 확인
git remote -v
원격 저장소 설정
# 기존 origin 제거 (만약 다른 저장소로 연결되어 있다면)
git remote remove origin
# 본인의 fork를 origin으로 추가
git remote add origin <https://github.com/개인계정/개인Repository.git>
# 원본 저장소를 upstream으로 추가
git remote add upstream <https://github.com/공통프로젝트(organization)/공통Repository.git>
upstream dev 브랜치 내용을 본인 main에 동기화
# 모든 원격 정보 가져오기
git fetch origin
git fetch upstream
# main 브랜치로 이동
git checkout main
# upstream의 dev 브랜치 내용을 main에 병합
git merge upstream/dev
# 병합된 내용을 본인 fork에 푸시
git push origin main
작업 후 커밋 및 푸시
# 작업 완료 후
git add .
git commit -m "커밋 메시지"
# 본인 fork의 main에 푸시
git push origin main

11/05(수)
- 회사 업무 처리하다가... AppleMail은 본문 이미지 처리 방식이 다르다는걸 알았다😧
일단 확인 요청의 요지는 동일한 메일을 pop3에서 받았는데도, 아웃룩에서 갖고간 건 본문에 이미지가 보이는데 회사포탈 메일에서는 이미지가 안보인다고 한다는 것이었다.
eml 파일 전달 받아서 확인해보니까 구조가 달랐다.. (회사 업무라 공개는 불가능하다 ^_^ㅠ)
| 문제점 1) 회사포탈에서 보는 메일 본문의 Content-Type은 text/plain 으로 되어있어서 이미지를 삽입할 수 있는 HTML 본문(text/html)이 없음 2) apple계정에서 보낸 이미지 파일은 Content-Disposition: inline으로, 본문에 삽입해달라고 요청하고 있음 => MIME 표준 규격에 따르면 이미지 본문 삽입 시 본문은 해당 이미지를 이미지 태그 형태로 참조할 수 있는 html 기반이어야 함(text/plain에서는 불가) 3) main 컨테이너가 Content-type: multipart/mixed로 되어있어서 이미지 파일을 본문과 독립된 일반 첨부파일로 인식하는 것으로 추정됨 |
알고보니까 꽤 이전부터 논쟁(?)이 되었던 내용이라고 한다.
- https://discussions.apple.com/thread/3209246?page=5&sortBy=rank
- https://discussions.apple.com/thread/2020972
그래서 아웃룩은 이미 이런거에 대한 처리를 했을지도..?🤔
이렇게 inline으로 요청 오는 건들은 샘플 데이터 몇 개 받아서 처리 방식을 변경해야겠다.
(apple.com을 메일 주소로 쓰는 계정은 보통 회사 계정이라고 한다. 우리 회사도 있는데 요청하면 알려 주시려나ㅠㅠ?)
11/06(목)
원래 오늘 회사 모각코 날이긴 한데 고객사 하나 반영 건이 있어서 야근 했다..
야근 전에도 업무들이 좀 있어서 후다다닥 헤치웠는데 갑자기 부장님이 오시더니 회사 동기가 담당하는 사이트 검색 도입 건 하나 있는데 가이드라인(이라고 했지만 사실상 초기 구축 + 샘플용 모듈 구축 + 가이드 + 이후 지원)까지 진행해줘야한다고 한다. 일정 되냐면서...

유지보수하면서 추가개발도 하고 개선하는건 맞는데, 내 업무도 갑자기 전조 없이 하루만에 통보로 변경하더니
이건 무슨 지금 업무도 하면서 기존 개발지원 업무도 같이 하라는ㅋㅋㅠ... 이거 한다고 내 현재 업무가 줄어든다거나 그런건 전혀 없다..
내가 너무 귀여운 탓이라고 하자 (๑>•̀๑) ꫂ ၴႅၴ
그래도 간만에 즐거울 것 같다. 한 동안 머리 깨지겠지~!
❅ *˚̩͙*‧₊̊‧*˚̩͙̩͙*‧₊̊‧*˚̩͙*‧₊̥‧*˚̩͙*‧*˚̩͙̩͙*‧₊̊‧*˚̩͙*‧‧*˚̩͙*‧₊̊‧* ❅
야근하고 집 와서는 40분 정도라도 강의 듣기.. 우리 회사는 커머스와는 관계 없기 때문에 실제 상황들을 좀 알고 싶었다.

다음 주까지 다 들어보자!
❅ *˚̩͙*‧₊̊‧*˚̩͙̩͙*‧₊̊‧*˚̩͙*‧₊̥‧*˚̩͙*‧*˚̩͙̩͙*‧₊̊‧*˚̩͙*‧‧*˚̩͙*‧₊̊‧* ❅
그리고 다시 모각코 zep으로 참여하기


같이 admin 만드는 프론트 담당 사원이랑ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 티키타카하기
11/07(금)
똑같은 로직인데 로컬은 되고 운영은 안되는 현상을 발견했다.. 설정 값 문제일까 싶어서 확인해봐도 아무리 봐도 모르겠더라.
단순히 데이터를 불러오는 쿼리인데도 로컬은 의도대로 잘 나오고, 운영은 계속 가장 상단의 특정 카테고리만 조회가 되어서 하루 동안은 이것만 본 것 같다^^ㅠ
SELECT *
FROM (
SELECT /*+ index_desc(idx) */
rowid,
ROW_NUMBER() OVER (ORDER BY date DESC) AS no_
FROM 테이블
WHERE (많은 조건 절...)
AND ROWNUM <= 5
) tbl
WHERE 1=1
AND no_ BETWEEN 1 AND 5
대략적인 쿼리는 위와 같다.
권한 쿼리 문제인가? 싶어서 조건절을 하나하나 소거법으로 지워가면서 확인했다.
저기서 발견한건.. ROWNUM 조건이 없어지는 순간 정상적으로 나오길래 이거구나 싶었다.
실행 계획을 비교하면 아래와 같았다!
운영
- SORT (ORDER BY) (Cost: 89): 실행 계획의 최상단 근처에 SORT (ORDER BY)가 있다.
- WINDOW (SORT PUSHED RANK): VIEW 하위에 WINDOW (SORT PUSHED RANK)가 있고, Oracle이 ROW_NUMBER() 함수를 처리하는 방식인데
여기서 SORT가 포함되어 있다는 것은 전체 결과를 정렬하려고 시도했거나, 적어도 많은 양의 데이터를 정렬한 후 상위 6건을 추출하려고 했음을 의미한다고 한다. - NESTED LOOPS 코스트 증가: 하위 조인 및 필터링 과정에서 NESTED LOOPS의 코스트와 카디널리티가 로컬보다 높게 책정되어 있어, 데이터 접근 및 처리 비용이 높다
로컬
- WINDOW (NOSORT STOPKEY): VIEW 하위에 WINDOW (NOSORT STOPKEY)
- NOSORT: 이 환경에서는 ROW_NUMBER()를 계산하는 과정에서 별도의 정렬 작업 없이 바로 데이터를 추출했음을 의미한다고 한다. 데이터 양이 적어서 그런 것 같다.
- STOPKEY: ROWNUM <= 5 조건을 매우 효율적인 Top-N 필터링으로 사용
로컬 환경에서는 데이터 양이 적고 실행 계획이 효율적이었기 때문에, ROWNUM <= 5 조건이 있음에도 불구하고 운 좋게 정확한 순서에 가까운 5건을 가져와 원하는 결과가 도출되었을 가능성이 높았던 것 같다. 즉, 실행 계획이 효율적이었기 때문에 결과가 '우연히' 맞았던 것.....
그러니까 로컬에서는 잘 나오지ㅠㅠㅠ
아무래도 그 이후에 조건 절로 no_ BETWEEN 1 AND 5 으로 따로 있으니까 ROWNUM을 지우는 방향으로 개선을 해봐야할지 검토해봐야겠다ㅜ
11/09(금)
오늘은 늘상 하는 모각코 모임에서, 회사 스터디 프로젝트를 진행했다!
core를 손 보고 admin을 만들고 있는데..
내가 만든 응답 구조 래핑이.. WebMVC 기반으로 만든거라 다른 사람이 만든 gateway에 적용이 안되고 충돌나는게 문제였다(gateway는 webflux로 구현됨ㅠㅠ)

기존 코드 좀 잘 보자............
'부스러기' 카테고리의 다른 글
| 왜 잘하는 엔지니어는 떠났고, 나는 왜 떠나기로 했는가 (0) | 2025.12.17 |
|---|---|
| (주간일지) 2025-11-24 ~ 2025-11-30 (0) | 2025.11.24 |
| (주간일지) 2025-11-17 ~ 2025-11-23 (0) | 2025.11.23 |
| (주간일지) 2025-11-10 ~ 2025-11-16 (0) | 2025.11.10 |
| 5년 만에 보는 면접 회고 (0) | 2025.08.28 |