공통코드의 단점

사실 공통 코드 도입자체는 어렵지 않다. 하지만 이로 인해서 복잡성과 성능에 관련된 고민이 생긴다.

공통 코드를 실제로 사용해보면 알겠지만 언젠가는 생각보다 이 패턴이 지저분하다는 생각, 그래서 어떻게 보완할지 고민이 들기 마련이다.

1. SQL이 복잡해진다.

테스트를 위해 데이터를 넣어보자.

-- ## 공통 코드의 단점

-- ### 공통 코드 사용 시 단점

DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS members;
DROP TABLE IF EXISTS common_code_attribute; -- 복습시 문제가 되는 테이블 제거
DROP TABLE IF EXISTS common_code_detail;
DROP TABLE IF EXISTS common_code_group;

-- 그룹 코드 테이블
CREATE TABLE common_code_group (
  group_code VARCHAR(50) PRIMARY KEY,
  group_name VARCHAR(100) NOT NULL
);

-- 상세 코드 테이블
CREATE TABLE common_code_detail (
  group_code VARCHAR(50) NOT NULL,
  code VARCHAR(50) NOT NULL,
  name VARCHAR(100) NOT NULL,
  sort_order INT NOT NULL DEFAULT 0,
  use_yn CHAR(1) NOT NULL DEFAULT 'Y',
  PRIMARY KEY (group_code, code),
  FOREIGN KEY (group_code) REFERENCES common_code_group(group_code)
);

-- 회원 테이블
CREATE TABLE members (
  member_id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL,
  grade VARCHAR(20) NOT NULL DEFAULT 'NORMAL'
);

-- 주문 테이블
CREATE TABLE orders (
  order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
  member_id BIGINT NOT NULL,
  order_status VARCHAR(20) NOT NULL DEFAULT 'ORDER',
  total_amount INT NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (member_id) REFERENCES members(member_id)
);

-- 결제 테이블
CREATE TABLE payments (
  payment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
  order_id BIGINT NOT NULL,
  payment_method VARCHAR(20) NOT NULL,
  payment_status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
  amount INT NOT NULL,
  FOREIGN KEY (order_id) REFERENCES orders(order_id)
);

-- 공통 코드 데이터
INSERT INTO common_code_group (group_code, group_name) VALUES
('ORDER_STATUS', '주문상태'),
('MEMBER_GRADE', '회원등급'),
('PAYMENT_STATUS', '결제상태'),
('PAYMENT_METHOD', '결제수단');

INSERT INTO common_code_detail (group_code, code, name, sort_order) VALUES
('ORDER_STATUS', 'ORDER', '주문접수', 1),
('ORDER_STATUS', 'PAID', '결제완료', 2),
('ORDER_STATUS', 'SHIPPING', '배송중', 3),
('ORDER_STATUS', 'DELIVERED', '배송완료', 4),
('ORDER_STATUS', 'CANCEL', '주문취소', 5),
('MEMBER_GRADE', 'NORMAL', '일반회원', 1),
('MEMBER_GRADE', 'VIP', 'VIP회원', 2),
('MEMBER_GRADE', 'VVIP', 'VVIP회원', 3),
('PAYMENT_STATUS', 'PENDING', '결제대기', 1),
('PAYMENT_STATUS', 'COMPLETE', '결제완료', 2),
('PAYMENT_STATUS', 'FAILED', '결제실패', 3),
('PAYMENT_STATUS', 'CANCEL', '결제취소', 4),
('PAYMENT_METHOD', 'CARD', '신용카드', 1),
('PAYMENT_METHOD', 'BANK', '계좌이체', 2),
('PAYMENT_METHOD', 'MOBILE', '휴대폰결제', 3);

-- 테스트 데이터
INSERT INTO members (name, email, grade) VALUES
('션', '[email protected]', 'NORMAL'),
('네이트', '[email protected]', 'VIP'),
('이순신', '[email protected]', 'VVIP');

INSERT INTO orders (member_id, order_status, total_amount, created_at) VALUES
(1, 'ORDER', 50000, '2026-01-15 10:00:00'),
(1, 'PAID', 75000, '2026-01-15 11:00:00'),
(2, 'SHIPPING', 120000, '2026-01-16 09:00:00'),
(2, 'DELIVERED', 85000, '2026-01-14 15:00:00'),
(3, 'CANCEL', 45000, '2026-01-13 14:00:00');

INSERT INTO payments (order_id, payment_method, payment_status, amount) VALUES
(1, 'CARD', 'PENDING', 50000),
(2, 'CARD', 'COMPLETE', 75000),
(3, 'BANK', 'COMPLETE', 120000),
(4, 'MOBILE', 'COMPLETE', 85000),
(5, 'CARD', 'CANCEL', 45000);

테스트 데이터를 위와같이 넣어뒀음.

공통 코드를 사용하지 않고 단순 조회 해보자.

SELECT 
	o.order_id,
    m.name AS member_name,
    o.order_status,
    o.total_amount
FROM orders o
JOIN members m ON o.member_id = m.member_id
ORDER BY o.order_id;

image.png

SQL만 보면 그냥 이해가 된다. 뭐를 의도하는 SQL인지 알수가 있음. 비즈니스관련된 SQL만 있어서 군더더기가 없어서 이해하는데 어려움이 없다.

여기에 이제 공통 코드 테이블을 끼얹어보자.

SELECT 
	o.order_id,
    m.name AS member_name,
    o.order_status,
    os.name AS order_status_name,
    o.total_amount
FROM orders o
JOIN members m ON o.member_id = m.member_id
JOIN common_code_detail os
	ON os.group_code = 'ORDER_STATUS' AND o.order_status = os.code
ORDER BY o.order_id;

image.png

결과집합은 전보다 더 보기 쉽다. 대신 SQL은 좀더 잘 이해가 안되기 시작한다. 그리고 심지어 여기서 끝이 아니다. 여기서 회원 등급까지 조회를 시작한다면? 그냥 컬럼만 넣는다면

SELECT 
	o.order_id,
    m.name AS member_name,
    m.grade, #이 컬럼만 추가하면 결과집합에 의미가 불충분해진다.
    o.order_status,
    os.name AS order_status_name,
    o.total_amount
FROM orders o
JOIN members m ON o.member_id = m.member_id
JOIN common_code_detail os
	ON os.group_code = 'ORDER_STATUS' AND o.order_status = os.code
ORDER BY o.order_id;