Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ORM을 활용할 경우의 설계, 개발 과정

9,149 views

Published on

SpringCamp에서 발표한 ORM 프레임워크를 활용했을 때의 설계 및 개발 과정을 담고 있다.

  • Be the first to comment

ORM을 활용할 경우의 설계, 개발 과정

  1. 1. Object Relational Mapping(이하 ORM) 기반 설계 및 개발 과정 박재성 www.slipp.net
  2. 2. 오늘 할 이야기
  3. 3. 요구사항 사용자는 질문을 할 수 있어야 한다. 질문에 대한 답변을 할 수 있어야 한다. 질문을 할 때 태그를 추가할 수 있어야 한다. 태그는 태그 풀에 존재하는 태그만 추가할 수 있다. 태그가 추가될 경우 해당 태그 수는 +1 증가, 삭제될 경우 해당 태그 수는 -1 증가해야 한다.
  4. 4. User Tag Question 1 0..n 0..n 1 1 0..n Answer 0..n 0..n
  5. 5. 어디서부터 시작할 것인가? 객체 or 테이블
  6. 6. 테이블 주도 개발
  7. 7. 테이블 설계로부터 시작 한다면… 요구사항 질문 할 때 태그를 추가할 수 있다. (예 java eclipse) 질문을 수정할 때 태그를 수정할 수 있다. (예. eclipse ant)
  8. 8. 질문 추가시 java eclipse 태그 추가할 경우 insert into question values( ?, ?, ?, ?, ?); => question_id = 1 select id, name from tag where name=’java’; => tag_id = 11 select id, name from tag where name=’eclipse’; => tag_id = 12 insert into question_tag values( 1, 11 ); insert into question_tag values( 1, 12 ); update tag set tagged_count = tagged_count + 1 where name=’java’; update tag set tagged_count = tagged_count + 1 where name=’eclipse’;
  9. 9. 질문 수정시 eclipse ant 태그 추가할 경우 update question set title=?, contents=? where question_id = 1; delete from question where question_id = 1; select id, name from tag where name=’eclipse’; => tag_id = 12 select id, name from tag where name=’ant’; => tag_id = 13 insert into question_tag values(1, 13); delete from question_tag where question_id=1 and tag_id=11; update tag set tagged_count = tagged_count + 1 where name=’ant’; update tag set tagged_count = tagged_count - 1 where name=’java’;
  10. 10. 객체 간의 관계는 사라지고 데이터베이스에 대한 처리에 집중하게 된다. 즉, 비즈니스 로직 구현 보다 데이터베이스 접근 로직 구현에 집중한다.
  11. 11. 도메인(객체) 주도 개발
  12. 12. 객체 설계로부터 시작 한다면… 요구사항 질문 할 때 태그를 추가할 수 있다. (예 java eclipse) 질문을 수정할 때 태그를 수정할 수 있다. (예. eclipse ant)
  13. 13. 일단 테이블 구조는 의식하지 않고 비즈니스 로직 구현한다.
  14. 14. 데모 질문 추가 1단계 – 태그 목록을 추출한다. • 쉼표(,)로 구분되어 있는 태그를 파싱한다.(예. java eclipse) • 태그가 태그 풀에 존재하는지 확인한다. • 태그 풀에 존재하지 않으면 태그를 신규 태그로 등록한다.
  15. 15. 데모 질문 추가 2단계 – Question에 태그 추가 • 태그 목록을 Question에 전달한다. • Question에 추가한 모든 Tag의 taggedCount를 +1 증가시킨다.
  16. 16. 데모 질문을 수정 • 질문 추가할 때와 같이 태그 목록을 구한다.(예. eclipse ant) • 추가된 태그는 Tag의 taggedCount를 +1 증가한다. • 삭제된 태그는 Tag의 taggedCount를 -1 감소한다.
  17. 17. 객체와 테이블 매핑
  18. 18. 데모 @Entity public class Question { @ManyToOne @org.hibernate.annotations.ForeignKey(name = "fk_question_writer") private User writer; @Column(name = "title", length = 100, nullable = false) private String title; @Temporal(TemporalType.TIMESTAMP) @Column(name = "created_date", nullable = false, updatable = false) private Date createdDate; } [...]
  19. 19. 테이블의 primary key와 이와 매핑되는 객체의 필드를 설계한다. @Entity public class Question { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long questionId; } [...]
  20. 20. 데이터베이스 성능에 대한 고려해 설계한다. @Entity public class Question { @ElementCollection(fetch = FetchType.LAZY) @CollectionTable(name = "question_content_holder", joinColumns = @JoinColumn(name = "question_id", unique = true)) @org.hibernate.annotations.ForeignKey(name = "fk_question_content_holder_question_id") @Lob @Column(name = "contents", nullable = false) private Collection<String> contentsHolder; public Question(User writer, String title, String contents, Set<Tag> tags) { this.writer = writer; this.title = title; this.contentsHolder = Lists.newArrayList(contents); processTags(tags); this.tags = tags; this.createdDate = new Date(); } [...] public String getContents() { if (isEmptyContentsHolder()) { return ""; } } } return Iterables.getFirst(contentsHolder, "");
  21. 21. 객체의 구조(특히 상속)와 테이블의 구조가 일치하지 않는 부분을 고려 해 설계한다.
  22. 22. 안정화 단계까지 ORM의 스키마 자동 생성 기반으로 개 발 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" [...]> <persistence-unit name="slipp.qna" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="create" /> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.show_sql" value="false"/> </properties> </persistence-unit> </persistence>
  23. 23. ORM 사용시 테이블 스키마 관리
  24. 24. 데모 public class JPASchemaExport { public static void main(String[] args) { Ejb3Configuration cfg = new Ejb3Configuration(); HashMap<String, String> props = new HashMap<String, String>(); props.put("hibernate.format_sql", "true"); Ejb3Configuration configured = cfg.configure("slipp.qna", props); SchemaExport se = new SchemaExport(configured.getHibernateConfiguration()); se.setDelimiter(";"); se.create(true, false); } } 객체와 테이블을 매핑하면 테이블 스키마를 자동으로 Export할 수 있다.
  25. 25. 데모 DB Migration 도구를 활용해 스키마 관리 Maven Carbon Five 플러그인 활용(https://code.google.com/p/c5-db-migration/)
  26. 26. 기능 추가 및 변경시 스키마 관리
  27. 27. 기능 안정화 단계 DB Migration 도구를 활용해 테이블 스키마 변경 관리한다. <?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence [...]> <persistence-unit name="slipp.qna" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.show_sql" value="false"/> </properties> </persistence-unit> </persistence>
  28. 28. 데모 요구사항 질문을 상세보기 할 때마다 조회수를 1 증가시킨다.
  29. 29. schema_version 테이블
  30. 30. 자바 진영에서 사용할 수 있는 DB Migration Tools • Flyway • Liquibase • c5-db-migration • dbdeploy • mybatis • MIGRATEdb • migrate4j • dbmaintain • AutoPatch
  31. 31. DB Migration Tools 시작 • http://flywaydb.org/에 각 도구별 비교 자료 확인 • 자신의 프로젝트에 적합한 도구 선정 • 개발 단계부터 DB Migration Tool 기반으로 개발해야 성공 가능성이 높다.
  32. 32. 데모 QnA 게시판 완료 - SLiPP
  33. 33. 마치며…
  34. 34. 도메인 주도 개발 객체 속성 추가 및 테이블 칼럼 추가 데이터베이스 접근 로직 구현 매핑 정보를 활용해 테이블 스키마 생 성 객체(도메인) 설계 비즈니스 로직 구현 객체와 테이블 매핑
  35. 35. 테이블 주도 개발 객체 속성 추가 및 테이블 칼럼 추가 비즈니스 로직 구현 데이터베이스 접근 로직 구현 테이블 설계 테이블로부터 객체 생성 객체와 테이블 매핑
  36. 36. 도메인 주도 개발 객체 속성 추가 및 테이블 칼럼 추가 데이터베이스 접근 로직 구현 매핑 정보를 활용해 테이블 스키마 생 성 데이터베이스 서버 필요함 객체(도메인) 설계 비즈니스 로직 구현 객체와 테이블 매핑 데이터베이스 서버가 없는 상태에서 개발 가능
  37. 37. 테이블 주도 개발 객체 속성 추가 및 테이블 칼럼 추가 비즈니스 로직 구현 데이터베이스 접근 로직 구현 테이블 설계 테이블로부터 객체 생성 객체와 테이블 매핑 데이터베이스 서버에 항상 의존관계를 가진다.
  38. 38. 도메인 주도 개발 데이터베이스에 의존하지 않은 상태에서 개발 가능한 시간이 있기 때문에 구현 – 피드백 사이클이 빠르다. 빠른 피드백 사이클은 삽질할 수 있는 시간을 확보함으로써 빠른 지식 축적이 가능하다. 지식 축적은 도메인에 최적화된 설계를 할 수 있도록 한다. 좋은 설계는 사용자의 요구사항 변화에 빠르게 대응할 수 있다. 개발자는 소스 코드에 대한 자부심과 여유 시간을 확보할 수 있다.
  39. 39. 질문 : 지금 내가 일하는 곳은 DBA의 영향력이 너무 커서 변화를 만들 수 없다. 어떻게?? 틈틈이 객체 설계, ORM에 대한 공부한다. 장난감 프로젝트를 하면 더 좋다. 몇 년이 지나 본인이 프로젝트를 주도할 때 도메인 주도 개발로 진행한다.
  40. 40. 질문 : ORM 적용하고 싶은데 팀장님이나 선배 개발자가 못하게 해요. 어떻게?? 틈틈이 객체 설계, ORM에 대한 공부한다. 장난감 프로젝트를 하면 더 좋다. 몇 년이 지나 본인이 프로젝트를 주도할 때 도메인 주도 개발로 진행한다.
  41. 41. 현재 내 영향력 하에서 변화를 만들 수 있는 부분에 집중하자. 점차 영향력을 확대해 나간다.
  42. 42. 질문 및 후기
  43. 43. www.slipp.net
  44. 44. 데모 소스 코드 • https://github.com/javajigi/slipping • 이 프로젝트의 slipp-qna 프로젝트 • orm_start부터 orm_step5 브랜치

×