오늘 배운 것

이전 포스트를 올린 지 1주일이 훌쩍 넘어가고 있어서 이대로 가다간 사이드 프로젝트를 아예 못 이어나가겠다는 위기감이 있었다. 사실 이걸 안 하더라도 기존 프로젝트의 '하위 투두 프롬프팅' 관련 작업이 또 남아서 시간이 넉넉하진 않지만, 중간발표와 디버깅에 많이 순위가 밀려있던 이 녀석을 좀 챙겨줘야 하겠다는 생각이 들었다. 

 

오늘의 목표는 기존 Django WAS에서 사용하고 있는 RDS DB에 영향을 주지 않고 Spring Entity에 똑같은 정보를 가져오는 것이다. (사실 마이그레이션이라는 표현이 맞는지는 잘 모르겠어서 쓰다가 아니다 싶으면 제목을 고쳐봐야겠다. -> 마이그레이션이 맞는 듯 하다.)

 

나름 잘 설명했다고 생각했는데, 처음에는 녀석이 직접 변환하는 방법을 추천해줬다... 다행히 추가적인 질의로 좋은 방법을 알아낼 수 있었다. 

모델 개수가 많지는 않은데 귀찮다고 하기 좀 그래서 많다고 했다

 

Django model을 Spring entity로 변환하는 방법에는 여러 가지가 있었다. 결론적으로 나는 3번 방법을 선택했다가 리버스 엔지니어링의 장벽을 느끼면 1번으로 돌아오기로 했다. 

 

1. Django model을 SQL script로 변환한 뒤, SQL script를 Spring entity로 변환하기

2. JHipster 라는 툴을 사용하면 SQL 스키마를 Spring entity로 변환할 수 있다고 한다. 다 좋았는데, 변환 파일을 작성할 때 JDL이라는 JHipster 자체 문법을 사용해야 한다고 해서 그 점이 진입장벽이었다. 

3. Hibernate에서 리버스 엔지니어링을 사용하면 기존 DB 스키마에서 Spring entity를 자동으로 생성할 수 있다고 한다. 

4. Django model 파일을 parsing해서 직접 Java 클래스 파일로 변환하는 스크립트를 짜는 방법도 있는데 너무 번거롭고 굳이 다른 도구가 있는데 사용할 필요가 없다고 느꼈다. 

5. Liquibase나 Flyway같은 도구가 있었다. 다 너무 좋은데 유료여서 포기했다. 


그런데 잠깐이지만 또 궁금한 게 생겼다. 내가 Hibernate와 리버스 엔지니어링의 정확한 정의를 모르고 있었더라. 

 

Hibernate란?

공식문서를 참고해봤다. Hibernate는 Java에서 사용하는 ORM 프레임워크다. ORM이란 객체(object)와 관계형 데이터베이스(relational DB) 사이를 연결(mapping)해 주는 기법이다. 즉 ORM이 없던 시절에는 DB에서 조회한 값을 별도의 객체로 들고 있지 못했고, 그래서 그 값을 읽거나 쓰는 작업을 하려면 여러 가지를 조심해야 했고, 코드도 많이 작성해야 했다. 특히 두 가지가 불편했다. 첫째로는 SQL을 매번 작성해야 했고, 둘째로는 DB에 코드가 의존하게 된다는 점이었다. 각 DB마다 문법(dialect)이 조금씩은 다르기 때문이었다. 

 

아무튼, 이런 ORM 기법을 Java 언어에서 사용하도록 해 주는 ORM 프레임워크 중 하나가 Hibernate였고, 사실상 대부분의 개발에서 Hibernate를 많이 사용한다고 알고 있다. 

 

리버스 엔지니어링(Reverse Engineering)이란?

그렇다면 리버스 엔지니어링(reverse engineering)은 또 뭘까. 대강 역방향으로 코드를 분석한다는 정도로만 알고 있었는데 세부적인 정의는 좀 더 달랐다. 소스 코드를 보지 않고 컴파일된 프로그램의 동작 방식을 이해하는 것이 리버스 엔지니어링 이었다. 또한 보통은 ORM을 통해 객체 모델을 데이터베이스 스키마로 변환하는데, 이 반대의 작업(지금 내가 하려는 거)도 리버스 엔지니어링에 해당한다. 꼭 '어떤 작업'만 리버스 엔지니어링이 아니라, 보통 순방향으로 이뤄지는 엔지니어링을 역방향으로 진행하는 것이 리버스 엔지니어링에 해당한다고 이해했다. 


다시 돌아가 보자!

 

나는 Hibernate Tools를 사용해서 리버스 엔지니어링을 하려고 한다. 우선 리버스 엔지니어링을 하려면 hibernate를 build.gradle 파일에 dependency로 추가해 주고, 'ORM 매핑에 필요한 기본 정보를 포함한 파일'과 '리버스 엔지니어링에 필요한 파일'을 만들어 줘야 한다. 

 

우선 다음 내용을 build.gradle 파일에 추가해 준다.

dependencies {
	implementation 'org.hibernate:hibernate-core'
	implementation 'org.hibernate.tool:hibernate-tools'
}

 

그리고 'hibernate.cfg.xml' 이라는 파일을 만들어 준다. 이 파일에서는 ORM 매핑에 필요한 기본 정보가 포함된다. (민감 정보가 포함되어 있기도 하고, 어차피 .gitignore에 포함되어 로컬에서만 존재할 파일이라 ID와 PW 등은 가렸다.)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/yourdatabase</property>
        <property name="hibernate.connection.username">yourusername</property>
        <property name="hibernate.connection.password">yourpassword</property>
        <property name="hibernate.hbm2ddl.auto">none</property>
        <property name="show_sql">true</property>
    </session-factory>
</hibernate-configuration>

 

또한 'reveng.xml' 파일도 만들어 준다. 이 파일에서는 리버스 엔지니어링에 필요한 기본 정보가 포함된다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
    <schema-selection match-catalog="yourdatabase"/>
    <table-filter match-name="*"/>
</hibernate-reverse-engineering>

 

그런데 코드 에디터(Intellij)에서 에러가 났다. 위의 두 XML 파일에서 참조하고 있는 .dtd 파일의 링크로 들어가 보니 해당 링크나 파일이 유효하지 않은 것 같았다. 찾아보니 DTD 파일이란 XML 문서에서 사용되는 구조와 규칙을 정의하는 문서라고 한다. 즉 XML 파일에서는 이 DTD 파일을 통해 어떤 규칙을 사용해야 할지 참고하려고 했는데 해당 링크가 유효하지 않아서 에러가 난 것으로 보였다. 

 

에러를 해결하고 마저 마이그레이션을 하고 싶었는데 밤이 늦었다... 일단 여기까지 세이브 해 두고 자야겠다!

 

 궁금한 점

1. 이 스프링 사이드 프로젝트를 진행하는 몇 가지 큰 이유 중 하나는 '똑같이 동작하는 WAS를 다른 프레임워크로 만들어 보면서 많이 배울 것 같아서'와 '스프링으로 만들면 취업에도 도움이 될 것 같아서' 였다. 그런데 막상 내가 '왜'를 놓치고 있다는 생각이 들었다. 단순히 스프링 쓰면 그걸로 끝일까? 물론 취업이나 현실적인 여건을 어느 정도 고려하는 건 당연하고 그럴 수는 있는데, 그냥 막연히 '스프링이니까!' 라고 쓰기엔 좀 2% 부족하다는 느낌이다... 왜 사람들은 스프링을 쓰는지에 대해서도 나만의 답을 내려보자. 

2. Hibernate의 구체적인 정의는 뭘까

3. 리버스 엔지니어링의 구체적인 정의는 뭘까

4. Django model이 바뀌면 Spring entity에 자동으로 반영해줄 수는 없을까? 역방향(Spring->Django)은 안 되고, 순방향(Django->Spring)으로만 반영되도록 자동화해주는 뭔가가 분명 있을 텐데 찾아봐야겠다. 

5. Hibernate와 JPA의 관계는? JPA는 또 뭐고 Hibernate랑은 어떤 관계가 있나?

 

+ Recent posts