[IF KAKAO 2021] <카카오톡 서버의 스프링 공화국 탈출기> 정리 및 후기
https://if.kakao.com/session/49
이 글은 IF KAKAO 세션 내용을 정리 및 후기를 적은 글입니다. 단순히 추후에 쉽게 보기 위해서 적는 글이지 내용을 도용하려는 의도는 없습니다. 해당 세션을 우선 보는 것을 추천드립니다.
해당 세션은 기존의 많이 사용하는 Spring Framework의 장단점과 이를 벗어나 다른 프레임워크를 사용해보는 것이 세션의 주 내용이었습니다. 여기서 Spring의 대체재로 사용된 것이 Ktor입니다. Kotlin을 기반으로 한 프레임워크라고 하는데 이후에 추가적으로 사용해보고 정리가 필요하다고 느꼈습니다.
Spring Framework의 장점
- 생태계가 잘 구성되어 있어 서버 개발 기간 단축
- 개발자 풀(Pool)이 넓어서 인력 추가 투입이 쉬움
- 프레임워크의 서비스 기간이 길어서 버전 업그레이드의 부담이 덜하다
- 스프링에 의존성을 가진 라이브러리가 많다
Spring Framework의 단점
- 인터넷 표준을 따르기 보다는 관습적으로 사용하는 것이 많다
- 빠르게 개정되는 인터넷 표준을 적극 반영할 수 없다
- ex. Challenge-Response Authentication (RFC7235) VS Spring AuthenticationProvider
- 대체재 - Ktor-Auth
- 라이브러리들이 스프링에 과도한 의존성을 가지고 있어서 의존성 관리가 쉽지 않다
- Java, Kotlin 개발자가 아닌 Spring 개발자가 되어가는 느낌이 있다
기존의 Spring Framework가 제공해주던 기능들
- Dependency Injection (의존성 주입)
- Database Integration (데이터베이스 연동)
- Interceptor & Filter
Spring의 기능을 대체하는 방법(Kotlin 기준)
- Spring이 아닌 다른 Web Framework 선택
- Spring -> Ktor 선택
- Spring에서 제공했던 기능들을 대체하기
Ktor
- 경량 서버 개발을 위한 프레임워크
- 필요한 기능은 프레임워크와 라이브러리를 사용해 구성
- 비동기 프로그래밍 모델을 제공
- Kotlin coroutine(코루틴)을 활용
Spring의 기능을 대체하기
1. Dependency Injection (의존성 주입)
Spring -> Koin
Spring Dependency Injection을 대체하기 위해 Ktor의 Koin을 사용합니다. Spring은 매우 많은 기능을 제공하지만 Koin은 기본적인 기능만 제공한다는 특징이 있습니다.
스프링의 Bean 생성 라이프사이클을 살펴보면 굉장히 많은 순서를 거칩니다. 하지만 이들의 기능을 활용하지 않는다면 불필요한 작업 들일뿐입니다. 따라서 기본적인 기능만 사용한다면 Koin이 더 적합할 수 있습니다.
Bean의 인스턴스 생성 방식도 비교를 해보겠습니다.
// Spring
@Bean
fun findUser() = FindUser(...)
// Koin
single { FindUser(...) }
여기서 볼 수 있는 Koin의 장점은 Annotation이 아닌 간단한 DSL 방식으로 작성이 가능하다는 점과 컨테이너가 Spring에 비해 가볍다는 점입니다.
2. Database Integration (데이터베이스 연동)
Spring JDBC -> Exposed
Spring에서는 JdbcTemplate등을 활용해서 SQL 쿼리를 String 형식으로 작성했습니다. Kotlin을 위한 경량 라이브러리인 Exposed를 사용하면 DSL 방식으로 작성할 수 있습니다.
// Spring JDBC
jdbcTemplate.query(
"SELECT * FROM posts WHERE chat_id = ? ORDER BY post_id DESC LIMIT ?",
...
)
// Exposed
Posts
.select { (Posts.chatId eq chatId) }
.orderBy(Posts.postId to SortOrder.DESC)
.limit(size)
이와 같이 Exposed를 사용하면 SQL을 DSL로 감싸 실수를 줄이고 명시적인 방법으로 쿼리를 작성할 수 있습니다. Spring에서도 물론 DSL 방식을 사용할 수 있습니다. 하지만 추가적인 라이브러리가 필요합니다. 하지만 Exposed는 기본적으로 DSL을 제공하고 coroutine도 지원합니다.
3. Interceptor & Filter
Interceptor & Filter -> Pipeline
Spring에서는 Interceptor와 Filter를 이용해 요청을 중간에 가로채 특정 처리를 할 수 있습니다. 그리고 이를 정해진 형식으로 제공하고 있습니다. 아래와 같은 순서로 진행되는데 이는 사용자가 임의로 변경할 수 없고 요청 처리를 하는 구간이 정해져 있어 제한적입니다.
Ktor에서는 이를 Pipeline으로 비슷한 기능을 제공하고 있습니다. Spring의 기능과 차이점은 요청을 다양한 방식으로 처리 가능하여 자유로운 구성을 할 수 있다는 장점이 있습니다.
Ktor에서는 5개의 Phase를 기본적으로 가지고 있고 중간에 다른 Phase를 추가하여 처리할 수 있습니다. Spring에서는 Filter 혹은 Intercepter에 추가하고 싶은 기능들을 넣어서 사용해야 했습니다. Ktor에서는 각 기능을 분리해서 작성 가능하고 원하는 Phase 구간에 넣어서 사용할 수 있습니다.
후기
우선은 길지 않지만 약 3년정도 Spring을 사용했던 저도 뭔가 대체재가 없을까 하고 생각만 했었죠. 이미 서비스되고 있는 프로젝트를 Kotlin으로 바꾸기도 쉽지 않은데 Framework를 바꾼다는 건 엄두가 나지 않았습니다. 그러나 이 세션이 눈에 들어온 것도 뭔가 제 생각에도 변화가 필요하다 느껴졌기 때문인 것 같습니다.
저는 이 세션을 보고 마지막으로 들었던 생각은 Ktor가 궁금하기도 했지만 다른 Spring 대체재 또 뭐가 있을까?라는 생각이 들었습니다. 이제는 프로젝트를 생성할 때 습관적으로 Spring Initializer를 선택하는 것이 아니라 어떤 프레임워크가 더 좋을까라는 생각을 하게 될 것 같습니다.
그럼 뭔가 Spring은 뒷방 늙은이가 되어가고 있는걸까요? 개인적인 입장이지만 앞으로 7~8년 내외 정도는 Spring이 지금의 위치를 버티고 있을 것 같습니다.
Spring 생태계도 계속 발전하고 있고 단순히 Spring MVC가 아닌 Spring 내에서 다른 방식으로 대체되는 경우도 많이 있기 때문이죠. 그리고 Spring 생태계는 많은 사용자로부터 검증이 많이 되었기 때문에 실제 유저들이 사용하는 서비스에 적용하기에 더 알맞을 수 있습니다. 위험한 도전을 하기엔 쉽지 않은 분야들도 많으니까요.
그럼에도 Spring이 아닌 다른 프레임워크로의 변화가 필요하다 느끼는 부분은 단순히 프로그램에 국한되는 문제가 아니라 개발자로서의 새로운 시도와 발전이 필요해서인 것 같기도 합니다.