https://kitaees.tistory.com/55
위 글에서 말한대로 8월 중후반에 우리 팀은 앱 스토어에 서비스를 출시하는데 성공했다. 하지만 개발자 입장에서 마냥 완벽한 서비스는 아니었다. 출시 기간을 더이상 늦추면 루즈해진다고 판단해 위험성을 감수하고 출시했기 때문이다. 아직까지 크리티컬한 운영 에러는 나오지 않지만 분명 9월이 되어 서비스 마케팅을 시작하면 트래픽이 증가해 수많은 에러가 나올 것이다.
그래서 팀 자체적으로 2023.09.01 ~ 2023.09.14까지 코드 리팩토링을 진행하기로 결정했다. 하지만 단순히 '리팩토링' 이라는 단어보다 나는 무엇을 어떻게 리팩토링 할 것인지 명확하게 하고자 지금 '텔링미' 서비스(서버팀)에 필요한 리팩토링이 무엇이 있는지 정리해보려한다.
😢 서버 구조
사실 서버 구조에 대해서 대단히 신경을 썼지만 부족했던 지식으로 했었고 이렇게 운영을 신경쓰진 못했었다.
지금 텔링미 구조를 간단하게 정리하자면 위의 그림과 같을 것이다. Backend 웹 서버 부분을 보면 우리는 지금 하나의 서버와 하나의 데이터베이스를 사용하고 있다. 그럼 텔링미 서비스는 트래픽이 몰릴 것에 전혀 대비를 안한 구조일까?
정답은 아니다, 나 또한 서버 설계 초반에 트래픽이 몰릴 것을 예상하고 있었고 'Scale Up' 방식으로 트래픽을 감당하고자 했다.
Scale Up 방식이란 수직적 규모 확장으로 한 대의 서버를 유지하면서 CPU, RAM 등의 성능을 높이는 방식이다.
나는 EC2 인스턴스의 유형을 t2.micro -> t2.medium으로 높이면서 트래픽을 감당하고자 했다. 하지만 이러한 방식의 단점으로는 자동복구(failover) 방안이나 다중화(re-dundancy) 방안을 제시하지 않는다.
이 말은, 서버 한대의 용량을 계속 높이더라도 이는 한계가 있고 또 만약 그 해당 서버가 다운이 되었을 때 대비책이 없어 막대한 피해를 입게 된다는 뜻이다.
그래서 이 'Scale Up' 방식은 단순한 서버 구조이면서 트래픽이 적을 때만 사용하고 대부분의 서비스는 'Scale Out' 방식을 사용한다.
'Scale Out' 방식은 위 사진처럼, 수평적 규모 확장으로 더 많은 서버를 추가하여 부하를 분산시켜 성능을 개선하는 방법이다. 위 사진처럼 'Load Balancer'를 이용해서 만약 서버1에 트래픽이 몰렸을 경우 서버2로 트래픽을 분산시키는 방식이다.
만약 위의 서버 구조에서 예기치못한 에러로 서버1이 다운되었다고 가정해보자. 그럼 'Load Balancer'는 자동적으로 서버1이 다운되었음을 인지하고 모든 트래픽을 서버2로 보낼 것이다. 개발자가 그 동안 서버1을 수리하고 자동적으로 배포를 이어간다면 사용자 입장에서는 서버가 다운되었는지 전혀 모를 것이고 편리하게 서비스를 이용할 수 있을 것이다.
우리 텔링미 서비스도 'Scale Up' 방식에서 'Scale Out' 방식으로 가는 것이 좋아보인다. 왜냐하면 우리는 대학생이기 때문에 24시간 서버 에러에 대응할 수 없기 때문이다. 위 사진처럼 서버 2대를 로드밸런서로 설계하는 것이 좋아보인다.
😭 Enum
위 사진의 코드를 간략하게 설명하자면, 매일 오후 6시에 푸시알림을 보내는 코드 로직이다. 여기서 눈여겨 봐야할 부분은 "모두의 공간", "많은 사람들이 좋아하는 답변이에요" 같은 단순 String 부분이다.
위 코드만 봐서는 뭐가 문제인지 모를 수도 있다. 하지만 우리는 신고 1번 당할 때, 신고 3번 누적되었을 때, 좋아요가 5배수 만큼 쌓였을 때.. 모두 푸시알림을 보내준다. 푸시알림을 보낼 때마다 위의 sendMessage()의 메소드를 호출하는데 전부 단순 String 부분을 위 사진처럼 넣어준다.
만약 위 String 부분의 내용이 바뀌면 어떻게 될까? 만약 "모두의 공간 HOT"에서 "우리의 공간 HOT"으로 바뀐다고 가정해보자. 그럼 저렇게 적힌 모든 부분에 찾아가 직접 바꿔줘야할 것이다. 변경점도 많고 상당히 귀찮은 일이다. 그래서 우리는 Enum을 써야한다.
푸시알림이 이렇게 확장성있게 쓰일지 모르고 Enum을 안썼지만 위 코드는 필히 Enum으로 사용되어 재사용성과 확장성을 겸비하는 코드로 바뀌어야한다.
😢 폴더 구조
위 사진을 보면 알 수 있듯이 우리 서버팀에서는 '도메인' 별로 폴더구조를 정리했다. 각 디렉토리 안에는 'domain', 'dto', 'repository', 'service', 'controller' 가 존재한다. 하지만 초반의 무분별한 기능 변경으로 인해 oauth와 jobInfo 등 경계가 흐려지는 폴더들이 생겨났고 계속 기능 개발에 들어가며 상당히 헷갈려지기 시작했다.
각 폴더는 확실히 '특정 일'을 하고 있어야하고 우리 개발자들이 알기 쉽게 되어있어야한다고 생각한다. 이런 점에서 볼 때 폴더 구조를 다시 정리하고 각 폴더의 '일'을 확실히 정의하는 것이 필요하다고 생각한다.
😢 Spring Security
현재 우리 서버팀에서는 클라이언트 단에게 accessToken을 넘겨받아 인증을 진행한다. 초반에 이 인증 과정에 대한 이해가 부족해 우리는 헤더에 accessToken : {accessToken} 이렇게 key를 accessToken으로 받았지만 대부분의 인증 단계에서는 Authorization을 이용하고 Bearer를 많이 붙인다.
위 포스트맨 사진처럼 Authorization이라는 키에 accessToken을 첨부하되 앞에 Bearer를 붙여주는 방식이다. Bearer는 개발자들끼리 소통하기 쉽게 '이것이 토큰이에요~' 라고 앞에 붙이는 것을 의미하는데 우리 서비스도 추후 확장되어 다른 개발자들과 일할 것을 염두해 이런 로직으로 바꿔야만 한다.
😢 Controller ResponseEntity 반환형
우리 모든 컨트롤러를 보면 ResponseEntity<?>로 반환형을 받고 있다.
여기서 ?는 와일드카드 타입으로써 타입 안정성을 위해 나온 기술인데 이 와일드카드 타입은 반환형이 명확하게 예측이 되지 않을 때 사용하는 것이 좋다고 생각한다. Swagger로 클라이언트와 통신하는 입장에서는 반환형을 명확히 하는게 좋다고 생각하기 때문에 위도 리팩토링 대상이라고 생각한다.
😢 감정, 신고 사유 등 인덱스 통일
우리 텔링미 서비스 특성 상, 답변을 작성할 때 감정을 입력하고 신고를 할 때도 사유를 받는다.
이 감정과 사유가 6가지가 되기 때문에 우리는 Integer 값으로 받았는데 소통 오류로 어떤 것은 1~6까지, 어떤 것은 0~5까지 받고 있다. 이는 클라이언트 단에서 상당히 헷갈릴만한 일이고 우리의 코드 작업에도 나쁜 영향을 끼칠 것이라 생각한다.
컴공 국룰로 0부터 시작하는 인덱스로 통일 리팩토링을 하는 것이 좋아 보인다.
😢 Service 간의 결합도
위 사진은 우리 ReportService 코드 일부분이다. ReportService 부분에 FirebaseCloudMessageService와 NoticeService가 관여하고 있는 것을 볼 수 있는데 단순히 Service가 다른 Service에 관여하는 것을 나쁘다고 볼 수 없지만 지금 우리 코드는 의존성이 강하다고 생각한다.
이는 코드가 얽혀서 유지보수하기 어려워지기도 하고, 의존성이 너무 강해 모듈 간의 결합도가 높아져 코드를 수정할 때 예상치 못한 부작용이 발생할 수 있다. 객체지향적으로 생각해도 좋지 않은 코드 구조이니 수정이 필수이다.
만약 FirebaseCloudMessageService 처럼 다른 Service에도 꼭 관여해야하는 서비스이면 Component로 따로 빼든지해서 리팩토링을 해야만 한다.!
😢 TestCase
우리 서버팀은 처음에 TDD 형식으로 짜기로 컨벤션을 정립했었다. 하지만 턱없이 부족한 구현 시간 때문에(변명..) 테스트 케이스를 거의 짜지 못했고 스웨거 등으로 테스트만 했다. 스웨거말고 테스트케이스로 짜야하는 이유가 무엇일까?
크게 생각나는 이유만 적자면 우선 스웨거로 테스트를 하면 DB에 기록이 남는다. 하지만 테스트 케이스로 @Transactional이라는 어노테이션을 붙이면 DB에 기록이 안남고 테스트를 할 수 있다. 또, 메소드 단위로 나눠 비즈니스 로직을 검증할 수 도 있고 스웨거로는 상당히 힘든 부하 테스트 또한 할 수 있을 것이다.
서버개발자에게는 테스트케이스를 짜는 것이 '매우매우!' 중요하므로 꼭 리팩토링을 통해서라도 추가해야 할 것이다.
이렇게 생각나는 리팩토링 대상들을 적어봤다. 대략 15일간의 기간동안 2일에 1개 꼴로 리팩토링을 완성해야해서 시간이 넉넉하지는 않다. 하지만 텔링미에 진심을 다하고 몰입하고 있는 만큼 개발팀의 코드는 항상 최선을 다해야한다고 생각한다. 리팩토링을 끝내고 '리팩토링 후기'로 다시 돌아올 수 있도록 하겠다!
'회고 & 후기' 카테고리의 다른 글
[회고] 테스트 코드 문화 도입기 (0) | 2024.03.21 |
---|---|
[후기] 신입 백엔드 개발자 취준 (2) | 2023.10.10 |
[회고] 창업팀에서 백엔드 개발자로서 앱을 출시하며 느낀점 (0) | 2023.08.20 |
[회고] 텔링미 로그인 스프린트 (0) | 2023.06.14 |
[후기] 넘블 챌린지 (0) | 2023.06.13 |