Service 계층 코드의 단어 단위 완벽 해체 및 동작 원리 파악
2026-03-27
오늘 한 것
BasicUserService클래스의 130줄 분량 코드를 단 한 줄도 빠짐없이, 자바 기본 문법과 영단어의 본질적 의미 단위로 해체하여 분석함.@Service,@Transactional,private final등 프레임워크와 자바의 핵심 키워드들이 컴퓨터에게 구체적으로 어떤 물리적 행동(메모리 등록, 묶음 처리, 접근 차단)을 지시하는지 파악함.Repository(창고 관리인),Optional(안전 상자),Exception(에러 폭탄) 등 추상적인 컴포넌트들의 실제 역할을 직관적인 행동 지침으로 번역하여 이해함.
막힌 점
- 스프링 프레임워크를 설명할 때 흔히 쓰이는 추상적인 전문 용어(IoC, 다형성, JPA 등)로 인해, 코드 각 줄이 실제로 어떤 역할을 하는지 와닿지 않아 7시간 가까이 분석에 난항을 겪음.
- 코드의 전체적인 흐름만 대충 짚고 넘어가면, 나중에 비슷한 코드를 다시 마주했을 때 스스로 해석하거나 응용할 수 없다는 한계를 느낌.
정리
- 코드는 뭉뚱그려진 마법이 아니라,
if(조건),throw(차단 및 에러 발생),save(저장)처럼 컴퓨터에게 차례대로 내리는 매우 직관적이고 구체적인 ‘명령서’들의 집합임. - 방어적 코딩의 중요성:
Optional로 빈 값을 방어하고,.existsBy...로 중복을 차단하며,@Transactional로 저장 도중 발생하는 에러를 원상 복구(Rollback)시키는 등 실무 코드의 대부분이 ‘안전장치’로 이루어져 있음을 깨달음. - 계층 간의 데이터 변환: 민감한 정보(비밀번호 등)가 담긴
User데이터베이스 원본 덩어리를 그대로 밖으로 내보내지 않고, 마지막에.toDto()를 통해 안전한 통신용 데이터로 변환해서 내뱉는(return) 흐름을 완벽히 숙지함.
코드
// 오늘 완벽하게 해체한 핵심 로직 중 일부 (컴퓨터에게 내리는 명령 번역본)
@Transactional // 이 아래 작업들은 한 묶음이다. 에러 나면 다 취소해라.
@Override // 규칙서(인터페이스)에 있던 내용대로 내가 덮어써서 만든다.
public UserDto create(UserCreateRequest userCreateRequest, Optional
// 1. 재료에서 텍스트(아이디, 이메일) 뽑아내기 String username = userCreateRequest.username(); String email = userCreateRequest.email();
// 2. 창고(DB)를 뒤져서 이미 존재하는 이메일/아이디인지 검사하고, 중복이면 에러 터뜨려서 가입 차단하기 if (userRepository.existsByEmail(email)) { throw new IllegalArgumentException(“User with email “ + email + “ already exists”); }
// 3. 사진 안전 상자(Optional)를 열어서, 사진이 진짜 있으면 이름/크기/알맹이를 뽑아 각각 창고와 저장소에 나눠서 저장하기 BinaryContent nullableProfile = optionalProfileCreateRequest .map(profileRequest -> { BinaryContent binaryContent = new BinaryContent(profileRequest.fileName(), (long) profileRequest.bytes().length, profileRequest.contentType()); binaryContentRepository.save(binaryContent); binaryContentStorage.put(binaryContent.getId(), profileRequest.bytes()); return binaryContent; }) .orElse(null); // 사진 안 올렸으면 그냥 텅 빈 값(null) 처리하기
// 4. 지금까지 모은 재료(아이디, 이메일, 비밀번호, 사진)로 최종 유저 데이터를 만들어 창고에 영구 저장하기 User user = new User(username, email, userCreateRequest.password(), nullableProfile); userRepository.save(user);
// 5. 비밀번호가 담긴 원본 대신 안전한 DTO 모양으로 변환해서 결과물로 내뱉고 끝내기 return userMapper.toDto(user); }