Spring Boot 협업(2)

제이 용·2025년 11월 25일

오늘은 저번 주에 마친 각자 API대로 적용을 시켜보려고한다.


트러블 슈팅(1)

  • 다만 도메인별 작업을 진행할 때 연관관계로 인해 특정 도메인이 없으면 테스트를 할 수 없는 상황을 생각하지 못했다.

  • 여러 도메인 별로 동시 작업을 하기 위해서는 어떻게 해야될까?

내 생각

  • 기본적인 CRUD 틀만 필요할정도 미리 만들어둔다.
  • 그걸 토대로 오류 없이 코드를 작성한다.

튜터님 피드백

  • 더미데이터 클래스를 활용해서 해보아라.
  • 시작함에 있어 필요 데이터를 테이블 생성을 해주어서 문제없게 해주는 것

더미데이터란?

  • 테스트나 개발 단계에서 실제 DB 데이터가 없을 때 임시로 넣어두는 데이터들을 만들어주는 클래스이다.

  • 처음에 받은 코드를 활용하여 우리가 쉽게 쓰기 위해 변경해 주었다.

package com.example.basic;

import com.example.basic.entity.Course;
import com.example.basic.entity.Student;
import com.example.basic.repository.CourseRepository;
import com.example.basic.repository.StudentRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;


@Component
public class DataInitializer implements CommandLineRunner {

    private final CourseRepository courseRepository;
    private final StudentRepository studentRepository;

    public DataInitializer(CourseRepository courseRepository, StudentRepository studentRepository) {
        this.courseRepository = courseRepository;
        this.studentRepository = studentRepository;
    }

    @Override
    public void run(String... args) throws Exception {

        // 수업 3개 준비
        Course backend = new Course("backend");
        Course frontend = new Course("frontend");
        Course pm = new Course("pm");

        // 학생 6명 준비
        // - backend 수업에 속한 학생 목록
        Student gygim = new Student("gygim", "gygim@example.com", 10, backend);
        Student steve = new Student("steve", "steve@example.com", 11, backend);
        Student alice = new Student("alice", "alice@example.com", 12, backend);

        // - frontend 수업에 속한 학생 목록
        Student isac = new Student("isac", "isac@example.com", 13, frontend);
        Student michell = new Student("michelle", "michelle@example.com", 14, frontend);

        // - pm 수업에 속한 학생 목록
        Student ian = new Student("ian", "ian@example.com", 15, pm);

        // 수업 생성
        courseRepository.save(backend);
        courseRepository.save(frontend);
        courseRepository.save(pm);

        // 학생 생성
        studentRepository.save(gygim);
        studentRepository.save(steve);
        studentRepository.save(alice);
        studentRepository.save(isac);
        studentRepository.save(michell);
        studentRepository.save(ian);
    }
}
  • 구조를 보아하니 레퍼지토리를 속성에 두고 생성자를 만든 후 오버라이드를 통해 프로젝트가 실행될 때 객체 생성을 통해 엔티티에 맞는 값을 넣은 후 save를 활용하여 데이터 테이블을 만들어주는 구조인 것 같다.

  • 우리는 유저 <- 게시물 <- 댓글 이기때문에 게시물을 만들기 위해 유저를 생성하고 댓글을 생성하기 위해 게시물이 필요했다.
package com.example.newsfeedproject;

import com.example.newsfeedproject.common.entity.Post;
import com.example.newsfeedproject.common.entity.User;
import com.example.newsfeedproject.post.repository.PostRepository;
import com.example.newsfeedproject.user.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.time.LocalDate;


@Component
public class DataInitializer implements CommandLineRunner {

    private final UserRepository userRepository;
    private final PostRepository postRepository;

    public DataInitializer(
            UserRepository userRepository,
            PostRepository postRepository
    ) {
        this.userRepository = userRepository;
        this.postRepository = postRepository;
    }

    @Override
    public void run(String... args) throws Exception {

        // 유저 없으면 생성
        if (userRepository.count() == 0) {
            User u1 = new User("user1", "user1@test.com", "1234", LocalDate.of(2001,6,11), "ㅎㅇ");
            User u2 = new User("user2", "user2@test.com", "12345", LocalDate.of(2000,5,12), "해윙");
            User u3 = new User("user3", "user3@test.com", "123456", LocalDate.of(2001,2,8), "할로");

            userRepository.save(u1);
            userRepository.save(u2);
            userRepository.save(u3);
        }

        // 게시글 없으면 생성
        if (postRepository.count() == 0) {
            User writer = userRepository.findAll().get(0);

            postRepository.save(new Post("제목1", "내용1", writer));
            postRepository.save(new Post("제목2", "내용2", writer));
        }
    }
}
  • 카운트를 활용하여 없을 경우에만 테이블이 생성되도록 구조를 바꿔주었다.

  • 별거 아니지만,, 코드를 읽고 어떻게 쓰면 되겠다고 구상까지 하게될 정도로 성장한게 뿌듯했다..


코드작성

  • 코드를 작성 간에 있어 여태 해온 CRUD 구조와 매우 흡사하였고 도전했었던 기능이 필수에 들어가게 되어 실험해볼 수 있는 시간이었다.

  • 다만 코드를 작성하면서도 머지를 했을 때 충돌이 일어나지는 않을까 라는 생각이 들었고, 인증인가 없이 코드를 작성하니 후에 추가 로직들이 생길 후환이 두려웠다.

  • 하지만 오늘 머지를 하게 됨으로써 많은 뿌듯함을 느낄 수 있었다.


느낀점

  • 생각보다 머지를 했을 때 오류는 적었고 수정할 코드의 소요는 적었다.

  • 스프링 부트와 자바란 것이 객체지향이 무엇이며, 튜터님들께서 말씀하신 설계가 잘되어진 코드가 무엇인지 느껴졌다.

  • 각자의 코드를 한 곳에 뭉쳤을 때 오류 없이 잘 진행된다는 것은 곧 더미데이터를 활용하여 충분한 테스트를 거친 코드였다는 것이고, 한 API에 오류가 터져도 다른 도메인에는 문제가 없다는 것은 곧 객체화가 잘 되어 있으며 분리가 잘 되어있다는 것이었다.

  • 이번 협업을 통해 혼자 코드를 짜는 프로젝트 때보다 더 많은 것을 느낄 수 있었다. 너무 재미 있었다.


배운점

지금은 기초적인 CRUD는 구현함에 있어 크게 어려움은 없었다.

  • 다만 JWT를 통해 인증/인가를 구현하면서 왜 보안에 취약하고 왜 타임설정을 해두는지 코드를 직접 구현해보고 팀원들과 뜯어보면서 몸소 알 수 있게 되었다.

  • 뿐만아니라 걱정했던 인증/인가 로직을 머지하게 됨으로써 다른 도메인들에 추가로직이 없을 때 당연히 오류가 있을 것이라고 생각했지만, 담당해주었던 분께서 필터까지 구현을 해주게 되면서 전혀 지장이 없는 것을 볼 수 있었다.. 너무 감사했고, 왜 잘 짜주신건지 설명까지해가며 무한 칭찬을 드렸다. 다른 팀원들도 인정하셨고 분위기가 좋았다.

남이짠 코드를 보며 문제를 해결하는 것은 굉장히 어려운 일이다.

  • 평소에 많이 배우던 입장으로 내 코드를 보고 단번에 해결을 해주시고 설명해주시는 다른 팀원분들께 고마움을 느꼈다. 내가 남에 코드를 보며 문제를 해결하려고 하니 정말 쉽지 않다는 것을 느꼈고, 남이 봤을 때도 보기 좋은 코드가 클린 코드라는 것도 알게 되었다. 신경써서 코드를 짜야겠다.

생각난 코드나 기발한 생각이 있다면 즉시 리팩터링하자.

  • DTO에 from같은 정적 메서드나 토큰을 활용하여 유저의 데이터를 뽑아오는 등 로직이 필요할 것 같다는 생각이 들면 바로바로 실행에 옮기는게 좋은 것 같다. 다만, 이미 구현이 되었고 더이상 추가할 로직이 없다는 가정 하에 하는 것이 좋다고 생각한다. 헷갈려서 꼬일 수도 있기 때문이다.

마지막으로 항상 배우기만 했던 내가 팀원들에게 설명해주고 가르쳐주고 같이 해결해나가는 모습을 보니 굉장히 성장을 많이 했다고 느꼈고, 앞으로도 더 많은 도움과 주변 사람도 같이 성장해가고 싶은 마음이 더 깊게 드는 날이었다.

0개의 댓글