순간을 성실히, 화려함보단 꾸준함을

긴 여정을 마치고....(토이 프로젝트 마무리) 본문

나의 개발 메모장

긴 여정을 마치고....(토이 프로젝트 마무리)

폭발토끼 2024. 3. 19. 10:17

안녕하세요.

정말 오랜만에 글을 작성합니다.

글또 9기에 참여를 하였지만,,,,,,글을 꾸준하게 작성하지 못해 이번 기수에는 실패한 것 같네요 ㅠㅠㅠㅠ

 

그럼에도 불구하고 글또와 별개로 토이 프로젝트를 마무리한 경험을 토대로 글을 작성해 보려고 합니다.

 

2024년 2월 날짜로 토이 프로젝트를 마무리 하였습니다. 이 프로젝트를 통해서 성과(?)는 아니지만 학습하고 적용했던 것들을 나열해보도록 하겠습니다.

 

1. java + spring boot + jpa + querydsl 조합으로 개발 진행

저는 현재 정통 대기업에서 sm (운영직무) 를 수행하고 있습니다. java 와 oracle database 를 다루고 있어 아무래도 java 를 기반으로 개발할 수 있는 spring boot 프래임워크를 선택하였습니다.(회사에서는 spring 도 사용 못하고 있습니다...ㅠ)

 

또한, 김영한님의 jpa 시리즈를 학습하고 이를 직접 체득하는 과정이 필요할 듯 싶어 jpa + querydsl 을 이용하여 개발하였습니다. 확실히 강의를 들을때와 달리 직접 개발을 하면서 부딧쳐야지 정말 제 것이 되는 것 같습니다.

 

프로젝트가 마무리가 될 때까지 큰 이슈 없이 해당 스택들로 개발을 끝낼 수 있었습니다.

 

2. email 전송 시에 비동기처리(@Async + @EnalbeAsync)

해당 프로젝트 기능 중에는 email 을 전송하는 기능이 있습니다. spring boot 의 JavaMailSender 클래스를 이용하여 메일을 보낼 수 있습니다. 이를 이용하여 이메일을 전송하는 api 를 개발하였는데.....이상하게 굉장히 늦게 응답을 하더라구요.

아마 외부 네트워크를 통해 전송을 하는 거다 보니 이메일 전송이 완료되고 응답되기까지 시간이 꽤 소묘되는 것 같았습니다.

 

만약 사용자가 이메일을 전송하고 완료되었다는 응답을 이렇게나 오랜 시간동안 대기 해야한다면 굉장히 불편함을 느끼겠죠?? 그리고 사용자입장에서는 실제로 이메일이 전송되는 시간보단 본인에게 이메일이 전송이 완료되었다는 응답을 받는 것이 더 포커스가 맞추어져 있습니다. 즉, 이메일이 실제로 전송되기만 하면 되는 것이지 살짝 늦게 전송되었다는 것에 대해 큰 불편함을 느끼지는 못하는 거죠.

 

그래서 이를 비동기 처리로 구현했습니다. 실제 이메일을 전송하는 task 와 사용자에게 이메일을 정상적으로 전송완료했다고 응답하는 task 를 분리하여 생각했습니다.

이렇게 개선을 하고 난 뒤 이메일 전송을 하였을때 바로 사용자에게 완료되었다는 응답을 보내주어 훨씬 서비스를 이용하는데 있어 불편함을 개선시킬 수 있었습니다.

 

@Async 어노테이션을 사용했습니다. 그러나 조금 더 찾아보니 @Async 어노테이션을 사용하는 것 보다는 AsyncConfigureSupport 를 상속받아 getAsyncExcutor() 를 재정의하는 것이 더 좋다고 합니다.

[출처 : https://dkswnkk.tistory.com/706]

 

저도 이번 기회에 실제로 비동기처리를 어떻게 구현하는지? SimpleAsyncTaskExecutor 와 ThreadPoolTaskExecutor 의 차이점이 무엇인지? 에 대한 내용을 학습할 수 있었습니다.

 

3. http 요청시 preflight 요청은 어떻게 처리해야 할까??

sop (same origin policy) 와 cors (cross origin resource sharing) 에 대해서는 다들 알고 계시죠???

해당 내용은 너무 중요하고 기본이라서 반드시 꼭 알고 가시길 바라겠습니다.

[참고 영상 : https://www.youtube.com/watch?v=6QV_JpabO7g]

 

cors 동작을 구현하는 방식 중에 가장 널리 사용되는 방법이 preflight request 인데요 실제 api 요청 전에 내가 전송할 요청이 정상적인지 아닌지를 확인받을 수 있는 선요청을 먼저 날리게 됩니다. 만약 유효한 요청이 아니라면 웹브라우저는 요청자체를 차단시키게 됩니다.

 

전 jwt 에 대한 검증을 spring interceptor 를 통해서 검증을 시도했습니다. 해당 토큰이 유효한지 아닌지를 체킹하는 로직인데 preflight 요청이 발생할때도 interceptor 로 요청이 들어가게 됩니다. 그러나 interceptor 에서는 해당 요청을 처리할 수 있는 기능이 없다보니 cors 에러가 발생하게 되더라구요.

 

interceptor 에서 preflight 요청이 발생했을때 처리할 수 있는 기능을 추가하였습니다.

CorsUtils.isPreFlightRequest 라는 객체를 사용해서 이 문제를 해결 할 수 있었습니다.

 

4. @EventListner 를 사용하여 의존성을 분리해 보자

일기방이 있고 일기방에는 사용자를 초대할 수 있습니다. 이때 초대받은 사용자에게 이메일을 전송하도록 기능이 짜여져 있는데요. 이 모든 기능을 하나의 task 에 담기에는 너무 많다고 생각이 되었습니다.

객체끼리도 의존성이 늘어나게 되고, 결합이 강해지게 된다는 단점이 존재합니다.

그래서 이를 뜯어내고 느슨한 결합 구조로 만들기 위해서 @EvnetListner 를 이용하였습니다.

 

일기방에 사용자를 초대하고 난뒤에 eventListner 에서 입력한 이메일들 주소로 메일을 전송하도록 구현했습니다.

이벤트를 처리할 인터페이스를 선언하고,

이벤트가 발생하면 처리할 구현체를 정의해 주었습니다.

ApplicationEventPublisher 에 publishEvent 메소드를 이용하여 정의한 객체를 파라미터로 넘겨주면 자동으로 이벤트가 실행되게 되는거죠.

 

이렇게 어쩌면 복잡할 수도 있는 로직을 @EvnetListner 를 통해서 결합성을 분리하여 해당기능을 구현할 수 있었습니다.

 

5. Test Code 는 왜 작성해야 되고, 어떻게 작성할 수 있을까???

이번 프로젝트에 다양한 test code 를 작성하려고 노력했습니다.

 

RestAssured 를 사용한 e2e test 

service layer 통합 테스트 작성

domain 별 query 작성 메소드 test 

 

위 과정에서 mocking,stubbing 도 해보면서 더 좋은 test code 는 무엇이고 어떻게 test code 를 작성할 수 있을까? 라는 생각들을 할 수 있었습니다.

https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C

 

Practical Testing: 실용적인 테스트 가이드 강의 - 인프런

이 강의를 통해 실무에서 개발하는 방식 그대로, 깔끔하고 명료한 테스트 코드를 작성할 수 있게 됩니다. 테스트 코드가 왜 필요한지, 좋은 테스트 코드란 무엇인지 궁금하신 모든 분을 위한 강

www.inflearn.com

위 강의를 통해서 학습했던 내용들을 직접 적용시켜 보았는데요, 너무나도 알차고 좋은 강의였습니다.

다른분들도 기회가 되시면 꼭 수강하시길 바라겠습니다.

 

또한, 매 테스트가 종료된 후 DB 에 남아있는 잔재들을 어떻게 초기화 시킬 수 있을지에 대해서 고민을 해보았습니다. 가장 첫번째로는 @Transactional 어노테이션을 사용하는 것이었는데 해당 어노테이션은 주의할 점이 있습니다.

https://velog.io/@balparang/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C%EC%9D%98-Transactional%EC%9D%80-%EC%A3%BC%EC%9D%98%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EC%9E%90

 

테스트 코드의 @Transactional은 주의해서 사용하자

테스트 코드에서 @Transactional을 사용할 때 생기는 부작용

velog.io

위 글을 참고해보세요!!!

 

그래서 @Transactional 을 사용하는 방법은 배제했습니다. 그러던 중 우아한tech 세미나 영상에서 아래와 같은 영상을 발견했습니다.

https://www.youtube.com/watch?v=ITVpmjM4mUE&list=PLgXGHBqgT2TtGi82mCZWuhMu-nQy301ew&index=26

 

영상이 조금 긴데 소스는 아래 링크를 타고 들어가시면 됩니다.

https://github.com/Harim2da/share-diary/blob/master/src/test/java/share_diary/diray/DatabaseCleanup.java

 

이번 글을 여기서 마치고 다음 글에서는 docker 를 사용해서 개발환경을 세팅한 경험, github Action 을 사용해서 CI/CD 를 구축한 경험, AWS ec2, route53, acm, load balancer 를 통해 운영서버에 배포와 https 를 적용한 경험 등등을 작성해보도록 하겠습니다.

 

글을 읽어주셔서 감사드립니다!