본문 바로가기

DevStory

프로젝트를 진행하며 - 2 -


1. 쿼리는 최대한 쉽게 작성해도 장표를 만들 수 있도록하자.. 그게 생산성이 높을 것 같다.

2. Domain 객체에서 값을 가지고 있고 그 값으로 계산을 할 수 있는 내용이라면 쿼리에서 계산하지 말고
Domain 객체 에서 자기 것을 계산해서 return해주도록 하자..( 이익%를 계산하는 방법은 Domain객체 자기가 알고
있으면 된다.)


3. 소계와 합계도 하나의 Domain객체로서 값을 가지고 있도록 만들자.. (쿼리에서 내지 말자.)
어차피 소계나 합계도 각각의 항목에 대한 값을 가지고 있는 하나의 Domain 객체일 뿐이다.

4. 표의 모양이 쿼리 결과에서 Row로 나온 항목들이 표의 컬럼으로 올라가야 한다면 쿼리에서 decode등을 사용해서 돌리도록 하지말고 쿼리 결과에서는 기본적인 Raw 데이터만 가져오고, 이것을 Pivot 된 표에서 뿌리기 편하도록 데이터를 다시 만들어내자.

이렇게 방향을 잡고 고민을 하기 시작했는데..특히 3번 같은 경우
소계와 합계를 하나의 Domain객체로 만들어 낼 것인지..

아니면, 각각의 카테고리에 대한 Domain 객체들을 가지고 있는 하나의 클래스를 설계해서 그 클래스로부터 소계와 합계
즉, instance.get합계() 혹은 instacne.get소계("의류") 이런식으로 그때그때 필요 할 때 호출해서 계산 된 결과를 가져오게 하는 것이 더 좋을까.. 하는 고민을 했습니다.

그러다 결국은 원래의 생각대로 3번 처럼 각각의 Domain객체로 표현하기로 했습니다.

그냥..그게 좀 더 쉬울 것 같아서.. -_-ㅋ..

일반적으로 DB에서 데이터를 가져와 화면에 뿌리는 경우에는 dto의 리스트나 배열을 가지고
loop를 돌면서 쭉쭉쭉~ 뿌려주는 방식을 많이 사용합니다.

표의 모양이나 쿼리가 어렵지 않으면 가장 쉽고 좋은 방법이겠지만
이번에 진행중인 프로젝트 같은 경우 앞의 포스트에서 처럼 테이블의 모양이 다양했고
각 그룹별 합계, 소계 그리고 하나의 페이지에서 평균값이나 누적값을 선택해서 보여주는 화면도 있었습니다.

이것을 모두 뷰에서 구현하려고 하면
if문을 사용해서 누적값을 보여줄때와 평균값을 보여줄때를 나눠서 구현하던가
쿼리를 두개 만들어서 누적값 가져오는 쿼리, 평균값 가져오는 쿼리를 사용해서 그때그때 다른 쿼리를 호출해야 할 것입니다.

그래서 평균이나 누적값 같은 경우는 dto에 평균/누적에 대한 boolean 필드와 평균을 구할 때 분모가 되는
일수를 필드를 둬서 dto에서 평균이냐 누적이냐에 따라서 해당 값을 return하도록 하기로 했습니다.

일단 DB에서 select를 했습니다.

소계나 합계등은 rollup같은 함수를 사용하면 쉽게 구할 수 있지만
어차피 뷰에서 그릴 표에는 소계나 합계가 각 그룹의 위에 올라가 있기 때문에 이것을 처리하기 위한 로직이
뷰에 들어가야 했습니다. 그래서 그냥 raw 데이터만 select를 했습니다.

총주문액,목표주문액,주문이익액,이익목표액,이익율,총주문건수,총방문자수,주문전환율

일단 이정도의 데이터를 화면에 뿌린다고 가정하면.. 쿼리를 통해

카테고리별 총주문액,목표주문액,주문이익액,이익목표액,총주문건수,총방문자수를 select 해옵니다.

이익율과 주문전환율은 각각

주문이익액/총주문액 * 100 , 그리고 총주문건수/총방문자수 * 100 이라는 식을 통해 계산될 수 있기 때문에
굳이 쿼리에서 계산하지 않고, DTO에서 위 식을 통해 해당 값을 리턴해 줄 때 계산해서 넘겨 줄 수 있도록
하기로 했습니다.

대략 이런정도의 result set이 나올 것입니다.

1depth 2depth 총주문액 목표주문액 주문이익액 이익목표액 총주문건수 방문자수
의류 점퍼 100000 500000 50000 50000 120 800
의류 바지 1020000 900000 200000 300000 321 820
의류 셔츠 3999000 400000 500000 600000 299 2000
의류 티셔츠 1029000 1000000 100000 200000 183 3994
의류 라운드티 3049200 1900000 43000 50000 184 1230
의류 청바지 1192834 3000000 120000 200000 192 4430
의류 치마 198840 1999000 5000 4000 300 1230
가전 TV 938291 1000000 12300 20000 284 1244
가전 냉장고 876634 490000 20009 40000 234 5660
가전 김치냉장고 7273847 19280000 420000 500000 594 1220
가전 카메라 2837818 18982000 120000 20000 899 3440
가전 오디오 498288 98112000 42000 30000 488 2388
가전 전화기 2781738 48911100 120000 100000 877 5777
가전 전자레인지 489378 3311000 23000 50000 299 3444
스포츠 운동화 182893 1233000 12000 40000 100 2899
(실제 금액과 전혀 관계없음 -_-)

이것이 화면에 보여질때는 아래와 같은 모양입니다. 일단 이게 가장 기본적인 장표였습니다.

     주문액 주문양  매장방문자수  ... 
 합계   XXXX원       
 의류 소계  XXXX원      
  점퍼 XXXX원      
  바지  XXXX원       
  셔츠  XXXX원       
가전 소계  XXXX원       
  냉장고  XXXX원       
  TV  XXXX원       
 ... ...         

그럼 우선 소계와 합계를 쿼리에서 만들지 않았기 때문에 이 소계와 합계를 어떻게 만들까가 우선 제일 먼저 해야 할 해결 과제였습니다.
그리고 두번째가 이 dto 리스트들을 어떻게 만들어야 뷰에서 뿌리기 좋을까.. 라는 거였죠..

일단 dto를 만들었습니다.
일단 소계와 합계라는 필드는 없습니다.
소계와 합계도 그 자체가 하나의 DTO로 만들려고 했기 때문이구요..
즉, 주문액, 주문양 등의 값들은 소계나 합계라고 해서 다른 것이 아니라 그냥 소계는 각 카테고리별 주문액,주문양의 합을
가지고 있을 뿐이고, 합계는 모든 result의 각각의 필드에 대해서 합을 가지고 있을 뿐이었습니다.

이것을 그냥 계산해서 가지고 있으면 되는거죠...

결국 합계건 소계건 TV건 셔츠건 주문액을 가져오고 싶으면

dto.get주문액();

 
이라는 것입니다.


금액계산이고, 나중에 합계와 평균을 경우 따라서 다르게 return해야 하기 때문에 BigDecimal을 사용했습니다.

일단 이렇게 하고, 모듈로서 사용 할 것이기 때문에 메뉴를 만드는데 필요한 depthId와 dephtName등은 상위 클래스를
하나더 만들어서 그녀석이 가지고 있도록 하고, 이를 상속해서 사용 할 수 있도록 하였습니다.


public class BaseDomain {

private String firstDepthName;
private String secondDepthName;
private String firstDepthId;
private String secondDepthId;

getter..
setter..

}

public class ResultDomain extends BaseDomain {

@RequiredSum
private BigDecimal 총주문액 = BigDecimal.ZERO;
@RequiredSum
private BigDecimal 목표주문액 = ...
@RequiredSum
private BigDecimal 이익액 =
@RequiredSum
private BigDecimal 목표이익액

private BigDecimal 이익율..

getter..
setter..
}

이런식의 모양이 되었습니다.
@RequiredSum은 제가 소계와 합계 dto를 만들기 위해 정의한 어노테이션으로 나중에 이 어노테이션이 붙은 필드에 대해서는
각 필드의 합을 구해서 소계dto와 합계 dto가 가지고 있을 수 있게 하였습니다.


일단 , 쿼리에서 select를 해서 위 dto의 list로 결과를 받아냈습니다.
이 list에는 합계와 소계 dto는 들어가 있지 않기 때문에, 이 list를 만져서 합계와 소계 dto를
넣어줘야 했고 그래서 이를 위한 table 클래스를 만들었습니다.

이 table 클래스는 쿼리에서 select해온 결과 리스트를 받아서
자기가 지지고 뽂는 과정을 거쳐 최종적으로

합계,(의류 - 소계),셔츠,티셔츠,치마, ... (가전 - 소계), TV, 냉장고, 김치냉장고, ...

이런 모양의 resultDtoList를 만들게 됩니다.

이 list의 순서는 위 표의 순서랑 동일하죠. 즉, 그냥 loop를 돌면서 해당 값을 뿌려주기만 하면 되게 됩니다.


그리고, 기본적인 모양은 비슷하겠지만 뷰에서 그려질 표는 보여줘야 하는 메뉴도 다를 것이고
(여기서는 주문액,주문건수 이런 내용이겠지만, 다른 곳에서는 uv,클릭수 등등 )
그래서 그런 메뉴를 만들어내는 메소드는 하위에서 알아서 구현 할 수 있도록 하고
기본적으로 dto의 리스트를 받아서 합계와 소계 dto를 만들어서 추가하는 부분을 구현하여 (즉, 위의 resultDotList를 만드는 과정)
상위 클래스에서 가지고 있고, 각 페이지마다 이 클래스를 상속받아 자기만의 테이블 상단 왼쪽 메뉴를 만드는
메소드를 구현해서 사용 할 수 있도록 하였습니다.