미뤄두고 미뤄두던 로그인 로직 리팩토링.. 더이상 미룰 수 없다고 생각해서 이번에 코드를 새롭게 갈아엎어보았다. 그 과정을 살펴보자!
기존 코드의 문제점 🤔
SOLID 원칙 위반
기존 코드의 가장 큰 문제점은 객체지향스럽지 못하다는 것이다.
위의 코드는 AuthService
의 코드 중 일부로 외부 네트워크와 통신하여 사용자의 정보를 받아오고 또 탈퇴하는 코드이다. 인자인 platform
은 사용자가 가입을 할 때, 클라이언트에서 어느 플랫폼으로 가입을 시도했는지 서버에게 보내준 enum 값이다. 이 코드의 문제점은 무엇일까? DIP와 OCP에 위배된다는 점이다. 만약, 기획의 요구사항의 변경으로 구글 로그인이 추가되었다면 어떨까? 구글 서버와 통신하기 위한 로직과 클래스를 생성해야하는 것은 물론이고, 이 AuthService
의 코드까지 수정해주어야 한다. 이는 명백히 OCP원칙에 위배되는 코드이다. 해당 문제는 코드가 추상체에 의존하지 않고, 구현체에 의존하기 때문에 발생하기 때문에 발생하는 문제라고 생각하였다.
간략하게 나타낸 것이지만 위 사진처럼, kakaoOAuthProvider
와 appleOAuthProvider
상위에 OAuthProvider
인터페이스를 만들고 각각을 구현체로 둔 후, AuthService
에서는 해당 추상체(인터페이스)에 의존하도록 한다면, 후에 로그인 플랫폼이 추가되더라도 AuthService
의 수정없이 요구사항을 반영할 수 있게 된다.
트랜잭션 내 외부 서버와의 통신
이에 대한 자세한 설명은 따로 글을 적어두었다.
한끼 로그인 코드의 문제점 <- 해당 글을 참고하자.
해결과정
인터페이스 생성
위에서 언급한대로 두 구현체 상위에 OAuthProvider
인터페이스를 만들어, 회원 정보를 받아오는 getSocialInfo
메서드와 requestRevoke
를 추상 메서드로 선언하였다.
그 후, 인터페이스를 주입시켜 모든 구현체들을 한꺼번에 빈으로 등록한 뒤 요청으로 들어오는 platform에서 빈 이름을 통해 구현체를 가져오도록 하는 방식으로 중개 클래스를 구현하였다.
짠! 코드가 훨씬 간단해졌다!
다만 한가지 문제점이 있었는데, 각 플랫폼마다 회원 정보를 받아올 때, 필요한 정보가 다르다는 것이다. 위 사진의 주석에도 적혀있듯이, oAuthProvider.requestRevoke
메서드에서, 첫번째 파라미터인 code
는 애플 로그인시에만 필요하고, 두번째 요소인 SerialId
는 카카오 로그인 시에만 필요하다. 하지만 requestRevoke
는 인터페이스의 추상 메서드이고 구현체들이 이를 오버라이드해서 구현하는 구조이기 때문에 2개의 인자 모두 파라미터 값으로 받아야하는 문제점이 존재했다. 이를 해결하기 위해, 파라미터 또한 인터페이스를 생성하여, 요청 플랫폼에 따라 전략 패턴을 적용해 요청 dto를 만들도록 할까 생각하였지만 현재 우리 프로젝트의 로그인 플랫폼은 단 2개 뿐이고, 이를 위해 클래스를 또 만드는 것은 너무 과하다는 생각이 들었다. 이 부분에 대해서는 후에 OAuth 요청 플랫폼이 증가하게 된다면 리팩할 예정이다.
트랜잭션 분리
이제 2번째 문제점이었던, 외부 서버와 통신하는 과정을 트랜잭션 범위에서 분리해보자. 외부 서버와 통신하는 과정을 다른 클래스로 분리해야 한다. 이를 구현하기 위해서 퍼사드 패턴을 도입하였다.
대충 흐름은 다음과 같다. 사용자의 요청이 들어오면 컨트롤러는 AuthFacade
를 호출한다. AuthFacade
에서는 OAuth2.0 기반의 사용자 인증을 수행한 후, AuthService
의 메서드를 호출한다. 이때, AuthService
의 메서드에는 트랜잭션을 적용하여 데이터의 일관성을 보장한다. 수정된 코드는 아래와 같다.
컨트롤러는 Facade
에 접근하여 요청에 따른 메서드를 호출하고, Facade
는 하위의 클래스들을 호출함으로써 내부호출 문제를 해결한 것이다.
마무리하며
이미 운영 중인 서비스이기도 하고, 로그인은 그 만큼 중요한 부분이기 때문에 리팩토링하기 무서웠다.. 유저수도 2000명이 넘고 멀쩡히 잘 돌아가고 있는데 괜히 고쳤다가 오류가 발생하면 어쩌지? 라는 생각도 있었고,,, 기존 코드 파일이 너무 많았기 때문에 사실 귀찮았던 것도 있다....ㅎ 하지만 걱정과 달리, 생각보다 리팩토링하는데 시간은 오래 걸리지 않았던 것 같다.
여전히 남들이 보기에 부족한 코드일지 모르지만 이렇게 계속 리팩하다보면 언젠가는 모두가 인정하는 클린코드가 되어 있지 않을까?
'대외 활동 > SOPT' 카테고리의 다른 글
스프링 트랜잭션과 전파 (0) | 2025.03.19 |
---|---|
중복 추가 이슈를 해결하기 위한 고민 (0) | 2025.03.19 |
비관적 락과 낙관적 락 (0) | 2025.03.19 |
애플 로그인 (0) | 2025.03.18 |
[아티클] SSH config를 통해 간편하게 SSH 연결하기 (0) | 2025.03.17 |