brunch

You can make anything
by writing

C.S.Lewis

by 최창규 May 20. 2018

카카오헤어샵의 프레임워크

Spring, Hibernate, Querydsl

카카오헤어샵은 Java 기반으로 개발되었고, 프레임워크는 Spring, ORM은 Hibernate, 정적 타입 SQL 도구는 Querydsl을 사용했습니다. 그러면 하나씩 기본적인 개념에 대해서 설명드리고 채택 배경에 대해서 말씀드리겠습니다.



Spring

카카오헤어샵은 2015년 8월에 프로젝트를 착수했습니다. 당시 모인 개발자들이 3명이었는데 각각 Java, Python, Ruby를 선호했었습니다. 우리는 논의를 통해 프로젝트를 Java로 하기로 결정했습니다. 왜냐하면 Java는 3명 모두 다룰 줄 아는 언어였고, 다른 개발자를 충원하기에 Java가 그나마 유리했기 때문입니다.


Java로 하기로 하면서 프레임워크는 자연스럽게 Spring으로 결정되었습니다. Spring의 뛰어난 자율성과 호환성에 끌렸기 때문입니다. Spring으로 하기로 하고 Research를 진행했는데 당시에 SpringBoot라는 프로젝트가 한창 이슈가 되고 있었습니다. SpringBoot는 Spring과 다른 별도 프레임워크가 아니라 빠르게 Spring 웹 애플리케이션을 만들 수 있도록 자주 쓰이는 설정과 라이브러리들을 모아 놓은 패키지라고 생각하면 이해가 쉬울 겁니다. SpringBoot를 try 해 보니 정말 웹 애플리케이션을 빠르게 만들 수 있어서 당시에는 센세이션 하다고 느꼈었습니다. 하지만 지금 돌이켜보면 SpringBoot의 기본적인 설정으로는 한계가 있고 카카오헤어샵 정도의 프로젝트를 진행하려면 Spring에 대해서 자세히 이해하고 있어야 가능합니다.



Hibernate

우선 ORM이라는 용어에 대해서 알아보겠습니다. ORM(Object Relation Mapping)은 OOP 언어와 DBMS 와의 상이한 시스템을 매핑하여, 쉽게 관련 프로그래밍을 도와주는 기술입니다. Java 진영에서는 여러 가지 ORM 프레임워크가 있는데 JCP에서 JSR220으로 표준으로 정리해서 배포한 것이 JPA입니다. JPA 구현체 중에서 가장 대중적인 것은 Hibernate와 EclipseLink인데 우리는 Hibernate를 사용하기로 했습니다. 그 이유는 Spring 진영에서 Spring-data-jpa 프로젝트로 Hibernate를 쉽게 사용할 수 있도록 지원하고 있기 때문입니다.

Spring-data-jpa는 Hibernate 뿐만 아니라 다양한 Spring Data Repository 인터페이스를 제공합니다. 이는 단순히 Interface의 method를 정의하는 것만으로 query를 대체할 수 있습니다. 예를 들어 findByName이라고 정의하면 "SELEC* FROM shop WHERE name = ?"와 동일한 구현을 할 수 있습니다.

그리고 Spring-data-jpa는 JPQL이라는 Query Language를 제공합니다. 예를 들면 "@Query("SELECT c FROM Country AS c") 와 같습니다.


우리는 Spring Data Repository 인터페이스를 사용했습니다. 하지만 복잡한 SQL은 Repository로 구현이 쉽지 않아 Querydsl을 함께 사용했습니다. 그리고 JPQL은 지양했습니다. 그 이유는 문자열로 구현된 QL이 리팩터링에 적절하지 않았기 때문입니다. 자세한 내용은 Querydsl 소개에서 다루도록 하겠습니다.



Querydsl

spring-data-jpa에서 제공하는 repository interface는 복잡한 SQL을 작성하기에는 한계가 있습니다. 그리고 JPQL은 문자열로 아래와 같은 형태로 개발을 해야 하기 때문에 유지보수도 어렵고 리팩터링에도 문제가 있습니다.

Query q =  em.createQuery("select o " +                 
                  " from Observation as o " +                 
                  " join o.eventID p" +                 
                  " join p.eventSetCollection ppp " +                 
                  " where o.individualID = :indiv " +                 
                  " and o.observationDate = :d " +                 
                  " and o.eventID= ppp.event.eventID" +                
                  " order by ppp.seqNum ASC" +                 
                  "");

그래서 찾은 대안이 Querydsl입니다. Querydsl의 예를 한 번 보겠습니다.

QPerson person = QPerson.person;  
Map<String, Integer> results = query.
                                                        from(person).
                                                        transform(
                                                        GroupBy.groupBy(person.firstname).
                                                        as(GroupBy.max(person.age)));

보는 바와 같이 Querydsl은 sql을 문자열이 아닌 Java Object와 method로 구현할 수 있습니다. 그리고 Type-safe 하기 때문에 컴파일 타임에 문제를 쉽게 확인할 수 있습니다. 물론 리팩터링에도 유리합니다.



cf. jooq

Querydsl과 비슷한 역할을 하는 프레임워크로 jooq(https://www.jooq.org/)가 있습니다. springboot 공식 reference에도 소개된 라이브러리입니다. 하지만 카카오헤어샵은 jooq를 사용하진 않았습니다. 그 이유는 select()의 응답 객체로 Querydsl은 @Entity 클래스를 return 하지만 jooq는 별도의 클래스를 만들어야 하기 때문입니다.



정리

카카오헤어샵은 서버 프레임워크로 Spring, Hibernate, Querydsl을 사용했습니다. 이번 브런치에서는 세부적으로 깊이 있는 내용을 다루진 않고 프레임워크를 채택한 이유에 대해서 얘기해 보았습니다. 프레임워크 별로 자세한 사용 방법은 별도의 매거진을 만들어서 브런치 하도록 하겠습니다. 궁금하신 내용이 있으면 댓글로 남겨주세요.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari