본문으로 건너뛰기

분양권 손피 계산기: 프리미엄 3,000만원이면 실제 부담액은?

· 약 11분
Alvin Hong
Alvin Hong
Senior Software Engineer

분양권 거래에서 “프리미엄 3,000만원”이라는 말만 보고 매수자 부담액을 판단하면 실제 준비해야 할 금액을 놓치기 쉽습니다. 손피 계약에서는 매도자가 손에 남길 프리미엄을 정하고, 매수자가 매도자의 양도소득세와 지방소득세를 대신 부담하기 때문입니다.

이 글에서는 손피가 일반적인 프리미엄 거래와 어떻게 다른지 설명하고, 1년 미만·1년 이상 보유기간과 세금 재산입을 반영한 계산기를 함께 제공합니다.

손피 계산기부터 확인하기

매도자 취득원가와 손에 남길 프리미엄, 인정 필요경비를 입력한 뒤 보유기간을 바꿔보세요. 기본값은 프리미엄 3,000만원·분양권 보유 1년 미만입니다.

SONPI TAX CALCULATOR

손에 남길 프리미엄을 입력해보세요

매도자의 양도세를 매수자가 대신 내는 경우, 대납세액을 다시 양도가액에 넣어 반복 계산합니다.

고정점 계산
빠른 예시
분양가·기납부금 등
억원
세금 대납 전 기준
만원

이 데모에서는 세금 대납 전 양도가액을 ‘취득원가 + 프리미엄’으로 단순화합니다.

양도일 기준
계약서·증빙 확인
만원

기본공제 250만원은 자동 반영합니다.

계약상 확정 정산액
만원

손피 세금에는 포함하지 않고, 매수자 필요자금에서 차감합니다.

매수자가 준비할 프리미엄 관련 순자금
1억 2,207만원

프리미엄 3,000만원 + 대납세액 9,207만원 + 중도금 이자 0만원

결합 세율77%국세 70% + 지방소득세 7%
1차 계산2,118만원대납세액을 아직 재산입하지 않은 값
반복 횟수641원 이내로 수렴
계산 결과
세금 대납 전 신고금액12억 3,000만원
양도소득세8,370만원
지방소득세837만원
매수자 대납세액9,207만원
매수자 부담 중도금 이자0만원
매수자 프리미엄 관련 필요자금1억 2,207만원
대납세액 포함 신고금액13억 2,207만원
왜 이렇게 계산되나요?

92,065,209원를 양도가액에 더한 뒤 다시 계산하고, 직전 결과와 1원 이내로 같아질 때까지 반복했습니다.

분양권의 실제 세율·필요경비·신고금액은 거래일, 자산 상태, 계약 내용과 법령 해석에 따라 달라질 수 있습니다. 이 데모는 손피의 고정점 구조를 이해하기 위한 참고 계산입니다.

이 데모는 세금 대납 전 양도가액을 매도자 취득원가 + 프리미엄으로 단순화합니다. 실제 계약에서는 취득일·양도일·기납부금·옵션비·필요경비·자산 상태를 별도로 확인해야 합니다.

계산기에 입력하는 금액의 의미

손피 계산에서 가장 자주 섞이는 숫자는 분양가, 양도가액, 프리미엄입니다. 계산기는 다음처럼 역할을 나누어 사용합니다.

입력값계산에서의 의미확인할 자료
매도자 취득원가매도자가 분양권을 취득하는 데 실제로 부담한 기준금액분양계약서, 납부내역, 옵션·확장 계약서
손에 남길 프리미엄세금을 납부한 뒤 매도자에게 남기려는 금액매매계약서 특약, 협의한 프리미엄
인정 필요경비양도차익에서 차감할 수 있다고 확인된 비용영수증, 세금계산서, 계약 관련 증빙
보유기간매도자의 취득일과 양도일 사이의 실제 경과기간취득일·양도일 증빙
매수자 부담 중도금 이자손피 세금과 별도로 매수자 필요자금에 더하는 금액이자후불제 약정, 정산서, 계약 특약

이 글의 데모에서는 세금 대납 전 양도가액 = 매도자 취득원가 + 손에 남길 프리미엄으로 계산합니다. 따라서 취득원가를 바꾸면 세금 대납 전 신고금액은 달라지지만, 취득원가와 양도가액을 같은 폭으로 바꾼다는 단순화 가정에서는 프리미엄에 대한 양도차익 자체는 그대로입니다.

취득원가에 포함되는 금액은 거래마다 달라질 수 있습니다. 기납부금·옵션비·확장비·중도금 이자·승계금액을 분양가와 같은 숫자로 묶으면 실제 양도차익과 신고금액이 어긋날 수 있으므로, 계약서와 납부내역을 나누어 확인해야 합니다.

손피란 무엇인가

손피는 ‘손에 남는 프리미엄’이라는 뜻입니다. 매도자가 세금을 납부한 뒤에도 약속한 프리미엄을 확보하도록 매수자가 매도자의 양도소득세와 지방소득세를 대신 부담하는 계약 조건을 가리킵니다.

일반적인 분양권 거래라면 프리미엄과 세금을 따로 보면 되지만, 손피에서는 매수자가 대신 낸 세금이 매도자에게 귀속되는 양도가액의 일부로 다시 계산될 수 있습니다. 그래서 프리미엄 × 세율 한 번으로 끝나지 않습니다.

1년 미만이면 왜 금액이 급격히 커질까

분양권은 보유기간에 따라 단기보유 세율을 적용합니다. **1년 미만 70%, 1년 이상 60%**라는 구분은 다주택 중과 가산세율이 아니라 분양권의 단기보유 세율입니다. 관련 세율 구조는 소득세법 제104조 현행 조문에서 확인할 수 있습니다.

계산기에서는 양도소득세에 지방소득세를 함께 반영합니다.

분양권 1년 미만: 양도소득세 70% + 지방소득세(양도소득세의 10%) = 과세표준의 약 77%
분양권 1년 이상: 양도소득세 60% + 지방소득세(양도소득세의 10%) = 과세표준의 약 66%

이 비율은 프리미엄 전체에 바로 곱하는 값이 아닙니다. 인정 필요경비와 기본공제 250만원을 차감한 과세표준에 적용하며, 실제 계산에서는 원 단위 절사와 양도일 기준 보유기간 판정이 함께 들어갑니다.

1년 경계는 하루 단위로 확인해야 한다

“1년 정도 보유했다”는 표현만으로는 세율을 정할 수 없습니다. 예를 들어 취득일이 2026년 1월 15일이라면 다음처럼 달라집니다.

취득일양도일완전 경과기간적용 구분
2026-01-152027-01-1412개월 미만1년 미만, 70%
2026-01-152027-01-1512개월1년 이상, 60%

계약일과 잔금일, 명의변경일 중 어느 날짜가 세법상 취득일·양도일이 되는지는 거래 구조에 따라 확인이 필요합니다. 계산기에서 날짜를 임의로 1년 뒤로 입력하기보다 실제 증빙에 맞춰 입력해야 하는 이유입니다.

세금 위에 다시 세금이 붙는 구조

손피의 핵심은 매수자가 대신 낸 세액을 양도가액에 다시 넣는 것입니다. 국세청도 2024년 11월 손피거래 관련 보도자료에서 매수자가 부담한 양도소득세 전액을 양도가액에 합산해 재계산하는 해석을 안내했습니다. 국세청 손피거래·다운거래 보도자료

대납세액을 T라고 하면 단순화한 고정점 식은 다음과 같습니다.

T = 적용세율 × (실질 양도가액 + T - 매도자 취득원가 - 인정 필요경비 - 기본공제)

우변에 다시 T가 들어 있으므로 계산기는 다음 순서로 반복합니다.

  1. 대납세액을 0원으로 두고 1차 세액을 계산합니다.
  2. 1차 세액을 양도가액에 더해 다시 세액을 계산합니다.
  3. 직전 결과와 1원 이내로 같아질 때까지 반복합니다.

세율 구간을 오르내리거나 필수 입력이 없으면 숫자를 임의로 확정하지 않고 계산 보류로 두는 편이 안전합니다.

반복 계산은 이렇게 진행된다

프리미엄 3,000만원, 필요경비 0원, 기본공제 250만원, 1년 미만을 단순화하면 결합세율은 약 77%입니다. 첫 계산 이후의 대납세액을 다시 양도가액에 넣으면 다음과 같은 흐름이 됩니다.

반복 단계직전 대납세액다시 계산한 대납세액
1차0원약 2,117만5,000원
2차약 2,117만5,000원약 3,748만원
3차약 3,748만원약 5,003만원
수렴직전 세액을 계속 재산입약 9,207만원

이 표의 1차·2차·3차 숫자는 설명을 위한 반올림값입니다. 실제 계산기는 원 단위 절사 후 직전 결과와 1원 이내로 같아지는 시점까지 반복합니다.

프리미엄 3,000만원이면 실제로 얼마인가

다음 조건을 가정해보겠습니다.

  • 손에 남길 프리미엄: 3,000만원
  • 보유기간: 1년 미만
  • 인정 필요경비: 0원
  • 기본공제: 250만원
  • 다른 감면·중과·신고 이슈는 제외

1차 계산에서는 과세표준이 3,000만원 - 250만원 = 2,750만원입니다. 양도소득세와 지방소득세를 합치면 약 2,117만5,000원이고, 프리미엄과 합친 금액은 약 5,117만5,000원입니다.

하지만 이 2,117만5,000원을 다시 양도가액에 넣으면 세액은 더 커집니다. 반복 계산이 수렴하면 대납세액은 약 9,207만원, 프리미엄과 합친 매수자 부담액은 약 1억 2,207만원 수준이 됩니다.

1년 이상 보유로 바꾸면 결합세율이 약 66%가 되어 같은 단순화 조건의 대납세액은 약 5,338만원, 프리미엄과 합친 금액은 약 8,338만원 수준으로 내려갑니다. 따라서 1년 경계는 단순히 세율 10%포인트 차이가 아니라, 대납세액이 다시 과세표준에 들어가는 반복 구조 전체를 바꾸는 기준입니다.

분양권과 등기 후 주택은 같은 계산기로 보면 안 된다

이 글의 핵심 예시는 분양권입니다. 분양권은 보유기간에 따른 단기세율을 중심으로 계산하고, 일반적인 1세대 1주택 비과세나 장기보유특별공제를 그대로 적용하지 않습니다.

반면 등기 후 주택은 보유기간 외에도 세대의 주택 수, 조정대상지역 여부, 다주택 중과 적용 여부, 거주기간과 비과세 요건이 함께 들어갑니다. 등기 후 주택을 손피로 거래한다면 분양권용 70%·60%만 대입해서는 안 되고, 별도의 양도소득세 조건을 다시 확인해야 합니다.

아파트 인사이트의 거래비용 계산기에서도 자산 상태에 따라 필요한 입력과 계산 보류 조건을 다르게 둡니다. 이 글의 계산기는 분양권 손피 구조를 이해하기 위한 전용 참고값으로 보는 것이 안전합니다.

국세청의 12억 취득·17억 양도 예시

국세청이 공개한 예시는 분양권을 12억원에 취득해 17억원에 양도하는 상황입니다. 1년 이상 보유한 분양권의 일반 양도에서는 양도차익 5억원에서 기본공제를 뺀 금액에 60%와 지방소득세를 반영해 약 3억2,800만원의 세금이 계산됩니다.

손피로 매수자가 이 세금을 부담하면 대납액이 양도가액에 들어가고, 다시 계산된 세금도 양도가액에 포함됩니다. 이 과정을 전액 부담 기준으로 반복하면 매수자가 부담할 양도소득세와 지방소득세가 약 9억6,600만원까지 커질 수 있습니다. 이 사례는 모든 손피 거래의 견적이 아니라, 대납세액 재산입이 누적될 때 금액이 얼마나 커질 수 있는지를 보여주는 공식 예시입니다.

계산기 상단의 국세청 12억 → 17억 버튼을 누르면 이 구조를 직접 확인할 수 있습니다.

손피 세액과 취득세·중개보수는 별도다

손피 대납세액은 매도자 양도소득세와 지방소득세를 매수자가 대신 부담하는 금액입니다. 취득세, 지방교육세, 농어촌특별세, 중개보수, 중도금 이자, 옵션·확장비까지 자동으로 포함한 총액이 아닙니다.

아파트 인사이트의 거래비용 계산기에서는 분양가와 프리미엄을 기준으로 취득 관련 비용과 중개보수를 별도로 계산하고, 손피 대납세액을 별도 항목으로 더해 보여주는 흐름을 사용합니다. 대납세액을 취득세 과세표준에 다시 넣을지는 거래 형태와 해석에 따라 확인이 필요한 영역이므로, 계산기에서 확인되지 않은 비용을 임의로 중복하지 않습니다.

중도금 이자는 일반적인 손피 계약에서 매수자가 함께 부담하는 경우가 많습니다. 그래서 이 글의 계산기에서는 중도금 이자를 손피 양도세 고정점에는 넣지 않고, 대납세액과 별도의 매수자 필요자금으로 더합니다. 이자후불제 약정, 이미 납부한 이자, 앞으로 승계할 이자, 매도자와의 정산액을 구분해서 입력해야 합니다.

자주 묻는 질문

프리미엄 3,000만원이면 5,000만원만 준비하면 되나요?

1차 세액만 더하면 약 5,118만원이지만, 손피의 대납세액 재산입까지 반영하면 단순화한 예시에서는 약 1억 2,207만원까지 올라갑니다. 5,000만원대는 최종 수렴값이 아니라 첫 번째 계산에 가깝습니다.

중도금 이자는 손피 세금에 합산하나요?

아닙니다. 매수자가 부담하는 중도금 이자는 매도자 양도세의 과세표준에 다시 넣는 손피 대납세액과 별개의 현금 지출입니다. 계산기에서는 대납세액을 먼저 고정점으로 계산한 뒤, 중도금 이자를 매수자 필요자금에 더합니다. 매도자가 이자를 부담하기로 한 경우에는 별도 정산액으로 차감하는 방식으로 계약 내용을 다시 확인해야 합니다.

70%는 다주택자 중과세율인가요?

아닙니다. 이 글에서 설명하는 70%는 보유기간 1년 미만 분양권에 적용되는 단기보유 세율입니다. 다주택 중과는 주택의 자산 상태와 조정대상지역, 세대의 주택 수 등 별도 요건을 검토합니다.

마이너스 피도 같은 방식으로 계산하나요?

마이너스 피는 손에 남길 양도차익이 발생하는 플러스 프리미엄과 구조가 다릅니다. 매수자가 매도자의 양도세를 대납하는 손피 고정점 계산의 대상인지 먼저 확인하고, 기준 분양가에서 차감되는 거래금액·미납금·이자·옵션비를 별도로 정리해야 합니다.

계산기 결과가 보류되면 무엇을 확인해야 하나요?

매도자 취득원가, 취득일, 양도일, 전매제한 해제일, 실제 거래 가능 여부처럼 결과를 바꾸는 핵심 근거가 빠졌는지 확인합니다. 전매제한이 확인되지 않은 상태에서 세액만 계산하면 거래가 불가능한 계약을 숫자로 포장할 수 있으므로, 계산 보류가 정상적인 안내일 수 있습니다.

계약 전에 따로 확인할 것

손피 계산기 결과만으로 계약을 진행해서는 안 됩니다. 다음 항목은 계산기 입력과 별도로 확인해야 합니다.

  • 기준 분양가와 프리미엄을 합한 세금 대납 전 실제 거래금액
  • 매도자의 실제 취득원가와 증빙 가능한 필요경비
  • 매도자 취득일과 거래 예정일
  • 분양권인지 등기 후 주택인지에 대한 자산 상태
  • 양도세를 매수자가 부담한다는 계약 특약
  • 전매제한 해제일과 실제 거래 가능 여부
  • 대납세액을 포함한 계약서·실거래 신고금액

손피 자체를 단순히 불법이라고 단정할 수는 없지만, 대납 세액을 제외한 금액으로 실거래를 신고하면 다운계약 문제가 생길 수 있습니다. 실제 계약과 신고 전에는 최신 공식 자료와 세무 전문가의 확인이 필요합니다.

아파트 인사이트에서 실제 조건으로 확인하기

아파트 인사이트에서는 단지 시뮬레이션의 거래비용 계산기에서 분양권 거래 조건을 따로 입력할 수 있습니다. 현재 분양권 전매가 가능한 신축 아파트처럼 전매제한 해제일과 매수 예정일을 확인할 수 있는 경우에는 거래비용 계산기에서 분양권 계산기가 활성화되어 기준 분양가·프리미엄·손피 대납세액을 함께 검토할 수 있습니다.

전매제한 해제일이 확인되지 않거나 매수 예정일이 제한기간 안이면 금액을 억지로 확정하지 않고 거래 가능 여부 확인이 필요한 상태로 표시합니다. 계산기에서 분양권 조건을 먼저 확인한 뒤, 이 글의 손피 계산기로 대납세액이 어떻게 누적되는지 이어서 비교하면 됩니다.

이 글은 먼저 발행한 아파트 매수·매도 거래비용 계산 가이드의 분양권·손피 내용을 분리해 확장한 글입니다. 전체 거래비용의 구조는 이전 글에서, 손피의 고정점 계산은 이 글에서 확인할 수 있습니다.

공신력 있는 참고자료

세율과 신고 기준은 개정될 수 있으므로, 아래 원문을 기준으로 거래일에 적용되는 내용을 다시 확인해야 합니다.

자주 묻는 질문 (FAQ)

Q. 분양권 손피(손에 남는 프리미엄) 거래란 무엇인가요?

손피 거래란 매도자가 양도소득세 등을 납부한 뒤 온전히 손에 쥐는 프리미엄 금액을 확정하고, 매도자가 부담해야 할 양도소득세와 지방소득세를 매수자가 대신 납부(대납)해 주는 분양권 거래 방식입니다.

Q. 분양권 단기 양도소득세율은 얼마인가요?

현행 세법상 분양권의 양도소득세율은 보유기간 1년 미만 시 70%(지방소득세 포함 약 77%), 1년 이상 보유 시 60%(지방소득세 포함 약 66%)의 중과 단일세율이 적용됩니다.

Q. 손피 계산 시 매수자가 대납한 세금을 왜 다시 양도가액에 합산(재산입)하나요?

세법상 매수자가 매도자의 양도소득세를 대신 부담하기로 약정한 경우, 대신 낸 1차 세금 또한 매도자의 실질적인 양도가액(경제적 이익)으로 보아 양도차익에 재산입되어 2차 세금이 계산되기 때문입니다.

함께 읽을 글

이 글과 계산 결과는 공개된 정책 기준과 입력 조건에 따른 참고용 정보입니다. 실제 세액·신고금액·거래 가능 여부를 보장하지 않으며, 투자 권유나 매수·매도 추천이 아닙니다. 최종 계약과 신고 전에는 최신 공식 자료와 전문가 의견을 확인하세요.

8.3 부동산 세제개편안, 보유세 계산기로 내 조건 비교하기

· 약 9분
Alvin Hong
Alvin Hong
Senior Software Engineer

2026년 8월 3일 발표된 부동산 세제개편안은 같은 아파트를 보유하더라도 실거주인지, 여러 채를 보유하는지, 공시가격이 어느 구간인지에 따라 결과가 달라지도록 설계되어 있습니다.

그래서 이번 글은 정책 요약만 하지 않습니다. 공시가격과 보유 조건을 직접 입력해 현행 세법, 2027년 중간 단계, 2028년 본격 시행안을 비교해볼 수 있는 계산기를 함께 준비했습니다.

먼저 계산해보기

아래 계산기는 시세나 호가가 아니라 세금 계산의 출발점인 공시가격을 입력받습니다. 결과는 정책안의 구조를 이해하기 위한 연간 추정치이며, 실제 고지서의 확정 세액을 대신하지 않습니다.

PUBLIC POLICY CALCULATOR

내 조건으로 보유세 차이를 비교해보세요

공시가격과 보유 조건을 입력하면 2026년 현행 기준과 8.3 정부안 기준의 연간 보유세를 같은 조건에서 비교합니다.

8.3 정부안
현재안과 단계별 정부안을 비교
시세가 아닌 공시가격 기준
억원

국토부 실거래가나 호가가 아니라, 세금 계산에 쓰이는 공시가격을 입력하세요.

대상 아파트를 포함해 입력
부부 공동명의 세액 최적 판정

부부 공동명의는 인별 9억 공제(총 18억)와 1주택 특례 중 세액이 작은 최적안을 자동 산출합니다.

거주기간 공제와 주택 비중에 반영
세부담 상한을 적용할 때만 입력
만원

ESTIMATE RESULT

2028년 정부안 본격 시행

연간 추정
예상 연간 보유세672만원재산세·종합부동산세·부가세 포함 추정치
현행 세법 기준710만원
선택 기준과의 차이−37만원
세목별 구성20억원 합산
재산세297만원
도시지역분126만원
지방교육세59만원
종합부동산세158만원
농어촌특별세32만원
이번 결과가 만들어진 과정공개 정책 기준
  1. 01

    합산 공시가격 20억원에서 기본공제 14억원를 뺍니다.

  2. 02

    남은 금액에 공정시장가액비율 70%을 적용해 과세표준 4.2억원을 구합니다.

  3. 03

    과세표준에 누진 세율을 적용하고 재산세 공제·세액공제를 반영합니다.

  4. 04

    전년도 세액을 입력했다면 세부담 상한을 적용합니다.

계산 결과를 읽는 법

이 계산기는 공개된 정부안과 일반적인 세목 구조를 바탕으로 한 콘텐츠용 추정치입니다. 공동명의, 특례주택, 지방세 감면, 실제 공시가격 확정값과 고지 방식에 따라 실제 세액은 달라질 수 있습니다. 정부안은 국회 심의와 하위법령 과정에서 바뀔 수 있으므로 계약·신고 전에는 원문과 세무 전문가의 확인이 필요합니다.

8.3 개편안에서 가장 중요한 변화는 ‘누구에게 적용되는가’입니다

이번 개편안을 단순히 “세금이 오른다” 또는 “세금이 내려간다”로 요약하면 실제 조건을 놓치게 됩니다. 정부의 공식 FAQ는 크게 네 가지 대상을 나눠 설명합니다.

1. 거주하는 1주택은 최대한 보호

거주용 1주택은 공시가격 14억 원까지 종합부동산세 과세 대상에서 제외하는 방향입니다. 공식 문답에서는 시가 약 20억 원 수준을 공시가격 14억 원 수준으로 환산해 설명하고 있습니다.

다만 “1주택이면 언제나 같은 혜택”이라는 뜻은 아닙니다. 일정 금액을 넘는 고가 주택은 별도의 세액공제 한도와 주택가액 기준을 적용하고, 실제 거주기간과 고령 여부 같은 조건도 결과에 영향을 줍니다.

계산기에서 만 나이·보유기간·거주기간을 따로 입력하게 한 이유가 여기에 있습니다. 같은 공시가격이라도 어떤 조건을 입력하느냐에 따라 적용되는 공제가 달라질 수 있습니다.

2. 비거주 1주택은 거주용 1주택과 분리

보유하고 있지만 거주하지 않는 주택은 거주용 1주택과 동일한 방식으로 볼 수 없습니다. 정부안은 비거주 1주택에 대해 기본공제를 9억 원으로 두는 방향을 제시하고 있습니다.

이 차이는 계산의 첫 단계에서 생깁니다. 세율을 적용하기 전, 공시가격에서 빼는 기본공제가 달라지기 때문입니다. 아래의 간단한 식을 보면 왜 공시가격이 과세표준으로 바로 이어지지 않는지 알 수 있습니다.

과세표준
= (주택별 공시가격 합계 - 조건별 기본공제) × 공정시장가액비율

계산기 결과의 “이번 결과가 만들어진 과정”에서 이 값들을 단계별로 확인할 수 있습니다.

3. 다주택은 주택 수와 거주 주택의 비중을 함께 봄

다주택자 계산에서는 단순히 공시가격을 모두 더하는 것만으로 충분하지 않습니다. 정부안은 다주택의 기본공제를 4억 원에 거주 주택의 공시가격 비중을 반영하는 방식으로 설계하고 있습니다.

예를 들어 여러 주택 중 한 채에 거주한다면, 그 주택이 전체 공시가격에서 차지하는 비중이 계산에 들어갑니다. 그래서 계산기에서 “실거주 주택”을 대상 아파트 또는 다른 주택 중 하나로 선택하도록 했습니다.

또 2028년 본격 시행 기준에서는 3채 이상 보유하거나 조정대상지역 주택이 포함되는지에 따라 공정시장가액비율이 달라질 수 있습니다. 이 조건을 모르면 같은 주택 수와 같은 합산 가격을 입력해도 결과를 잘못 읽을 수 있습니다.

4. 바로 한 번에 바뀌지 않고 단계적으로 적용

정부안은 시장과 납세자의 적응을 고려해 종합부동산세를 2년에 걸쳐 단계적으로 개편하는 방향입니다. 계산기에서는 다음 세 시점을 분리했습니다.

  • 2026년 현행 세법 기준: 현재 적용 중인 기준과 비교하는 기준선
  • 2027년 정부안 중간 단계: 개편이 시작되는 중간 단계
  • 2028년 정부안 본격 시행: 정부안이 제시한 본격 시행 단계

따라서 2028년 결과만 보고 “내년부터 바로 이 금액을 낸다”고 해석하면 안 됩니다. 개정 법률안은 입법예고와 국회 심의, 하위법령 확정 과정을 거치며 내용이 바뀔 수 있습니다.

계산식은 왜 여러 단계로 나뉠까

보유세는 하나의 세율을 공시가격에 곱하는 계산이 아닙니다. 이 계산기는 앱의 보유세 추정 흐름과 같은 순서로 다음 요소를 누적합니다.

1. 공시가격을 합산

대상 아파트와 다른 주택의 공시가격을 합산합니다. 세금 계산에서 사용하는 가격은 실거래가·호가와 다를 수 있으므로, 화면에 표시된 기준연도와 공시가격을 확인해야 합니다.

2. 조건에 맞는 기본공제 적용

1주택인지, 거주 중인지, 여러 채를 보유하는지에 따라 기본공제가 달라집니다. 이 단계에서 과세 대상 여부가 갈립니다. 합산 공시가격이 과세 기준에 미치지 않으면 종합부동산세 과세표준은 0원이 될 수 있습니다.

3. 공정시장가액비율로 과세표준 계산

기본공제를 뺀 금액에 공정시장가액비율을 적용합니다. 이 값이 실제 세율을 곱하는 과세표준입니다.

과세표준 = max(0, 공시가격 합계 - 기본공제) × 공정시장가액비율

4. 누진세율과 재산세 공제 적용

과세표준이 계산되면 구간별 누진세율을 적용합니다. 이후 종합부동산세 계산에서 이미 반영된 재산세 부분을 조정하고, 대상이 되는 경우 1주택 세액공제를 반영합니다.

그래서 계산기에는 종합부동산세만 표시하지 않고 재산세·도시지역분·지방교육세·농어촌특별세를 나눠 보여줍니다. 총액만 보면 정책안 때문에 바뀐 부분과 원래 함께 내는 세목을 구분하기 어렵기 때문입니다.

5. 전년도 세액이 있으면 세부담 상한 확인

전년도 보유세를 입력하면 계산기에 세부담 상한을 반영할 수 있습니다. 전년도 세액을 입력하지 않으면 이 단계는 적용하지 않습니다.

이 입력란을 필수로 만들지 않은 이유도 있습니다. 실제 고지된 전년도 세액을 모르는 상태에서 임의의 숫자를 넣으면 오히려 결과가 부정확해지기 때문입니다.

계산식을 한 줄씩 따라가 보기

계산 결과를 제대로 읽으려면 최종 금액보다 중간 숫자를 먼저 봐야 합니다. 계산기에서 입력값이 바뀔 때마다 실제로 달라지는 부분은 크게 합산 공시가격 → 기본공제 → 공정시장가액비율 → 누진세율 → 공제·세액공제 → 세부담 상한의 순서로 이어집니다.

1. 과세표준을 먼저 만든다

먼저 대상 아파트와 다른 주택의 공시가격을 합산합니다. 그다음 주택 수와 거주 여부에 맞는 기본공제를 빼고, 남은 금액에 해당 연도의 공정시장가액비율을 적용합니다.

총 공시가격 = 대상 아파트 공시가격 + 다른 주택 공시가격의 합
과세표준 = max(0, 총 공시가격 - 기본공제) × 공정시장가액비율

max(0, ...)는 공제액을 뺀 결과가 음수가 되지 않도록 0으로 처리한다는 뜻입니다. 따라서 공시가격 합계가 과세 기준에 미치지 않으면 과세표준과 종합부동산세 산출세액이 0원이 될 수 있습니다.

2. 누진세율은 전체 금액에 한 번에 곱하지 않는다

과세표준이 4억 2천만 원이라고 해서 4억 2천만 원 전체에 하나의 세율을 곱하는 방식은 아닙니다. 각 구간에 들어가는 금액을 잘라서 구간별 세율을 적용한 뒤 더합니다.

누진 산출세액
= 1구간 금액 × 1구간 세율
+ 2구간 금액 × 2구간 세율
+ 3구간 금액 × 3구간 세율 ...

예를 들어 2027년 정부안, 거주 1주택, 공시가격 20억 원을 가정하면 계산기 구조는 다음처럼 읽을 수 있습니다.

단계계산결과
총 공시가격20억 원20억 원
기본공제14억 원6억 원이 남음
공정시장가액비율6억 원 × 70%과세표준 4억 2천만 원
구간별 산출3억 × 0.5% + 1억 2천만 원 × 0.7%234만 원

여기서 234만 원은 재산세 공제·1주택 세액공제·세부담 상한을 반영하기 전의 종합부동산세 산출 단계 예시입니다. 실제 계산기의 최종 보유세는 재산세와 부가세목을 함께 계산하므로 이 숫자와 같지 않습니다.

3. 재산세와 종합부동산세를 따로 계산한 뒤 합산한다

계산기는 종합부동산세만 계산하지 않습니다. 주택별 재산세를 먼저 계산하고, 도시지역분과 지방교육세를 더한 다음, 종합부동산세에서 공제되는 재산세와 세액공제를 반영합니다.

재산세 과세표준 = 공시가격 × 재산세 공정시장가액비율
도시지역분 = 재산세 과세표준 × 도시지역분 세율
지방교육세 = 재산세 × 지방교육세율
농어촌특별세 = 최종 종합부동산세 × 20%

연간 보유세
= 재산세 + 도시지역분 + 지방교육세
+ 최종 종합부동산세 + 농어촌특별세

종합부동산세에서 빠지는 재산세 부분은 같은 세원을 두 번 과세하지 않기 위한 조정입니다. 그래서 과세표준 × 누진세율로 나온 금액이 그대로 최종 종합부동산세가 되지 않습니다.

4. 1주택 세액공제는 산출세액에 적용한다

1주택에 해당하는 경우에는 연령·보유기간·거주기간에 따라 세액공제율이 달라질 수 있습니다. 계산기에서는 해당 조건으로 계산한 공제액을 산출세액에서 빼고, 정부안 단계에서는 별도 공제 한도도 적용합니다.

세액공제 후 종합부동산세
= max(0, 산출 종합부동산세 - 재산세 공제 - 1주택 세액공제)

나이·보유기간·거주기간을 입력하지 않으면 관련 공제가 충분히 반영되지 않을 수 있습니다. 반대로 조건을 임의로 높여 입력하면 실제 증빙 요건을 충족하지 않아 결과가 달라질 수 있으므로, 확인 가능한 값만 입력해야 합니다.

5. 전년도 세액이 있으면 세부담 상한을 마지막에 확인한다

전년도 보유세를 입력한 경우에는 올해 계산액이 전년도보다 일정 비율 이상 커지지 않도록 상한을 확인합니다. 계산기의 구조를 단순화하면 다음과 같습니다.

허용 보유세 = 전년도 보유세 × 해당 기준의 상한비율
상한 적용 후 세액 = min(상한 적용 전 보유세, 허용 보유세)

실제 계산에서는 재산세처럼 이미 고정된 세목을 먼저 제외하고 종합부동산세와 농어촌특별세 쪽을 조정합니다. 전년도 세액을 입력하지 않으면 이 단계는 건너뜁니다.

입력 조건이 바뀌면 어느 식이 달라질까

입력 조건계산에서 달라지는 부분
명의 형태 (단독 / 부부 공동명의)인별 9억 공제(총 18억)와 1주택자 특례 신청(12억/14억+세액공제) 중 최적 세액 자동 선택
다른 주택 공시가격총 공시가격, 주택 수, 기본공제와 누진 구간
실거주 주택 선택거주 주택 비중에 따른 공제와 1주택 여부
만 나이1주택 고령자 세액공제율
보유기간·거주기간장기보유·장기거주 세액공제율
3채 이상·조정대상지역 주택정부안의 공정시장가액비율과 세율 조건
전년도 보유세세부담 상한 적용 여부와 상한 조정액

따라서 같은 아파트의 공시가격을 입력하더라도 다른 주택을 추가하거나, 실거주 주택을 바꾸거나, 전년도 세액을 입력하면 최종 금액이 달라질 수 있습니다. 계산기를 사용할 때는 총액만 캡처하기보다 공시가격 합계·공제액·과세표준·공정시장가액비율·공제액·상한 조정액을 함께 기록하는 편이 좋습니다.

결과를 읽을 때 확인할 네 가지

  1. 공시가격 기준일: 내가 입력한 숫자가 어느 기준연도의 공시가격인지 확인합니다.
  2. 거주 주택 선택: 여러 주택을 보유한 경우 어느 집에 거주하는지에 따라 공제 구조가 달라집니다.
  3. 현행 기준과 정책안의 차이: 선택한 단계의 총액보다 현행 기준과의 차이를 먼저 봅니다.
  4. 정부안과 확정 세법 구분: 계산기의 2027·2028 결과는 정부안 시나리오이며, 확정 고지세액이 아닙니다.

특히 계산기에서 +로 표시되는 차이는 정부안 기준 추정치가 현행 기준보다 높은 경우이고, 로 표시되는 차이는 낮은 경우입니다. 어느 쪽이든 결과만으로 매수·매도 결정을 내리는 것이 아니라, 공시가격·거주 여부·주택 수를 바꿔가며 민감도를 확인하는 용도로 사용하는 편이 안전합니다.

자주 묻는 질문 (FAQ)

Q. 8.3 세제개편안에서 거주용 1주택 종부세 면제 기준은 얼마인가요?

정부안 기준으로 실제 거주하는 1세대 1주택자는 공시가격 14억원(시가 약 20억원 수준)까지 종합부동산세 과세 대상에서 제외하는 방향이 제시되었습니다.

Q. 비거주 1주택과 거주용 1주택의 기본공제는 어떻게 다른가요?

보유하지만 실거주하지 않는 1주택은 기본공제 9억원이 적용되어 거주용 1주택(14억원)과 분리하여 과세됩니다.

Q. 다주택자의 종합부동산세 개편은 언제부터 적용되나요?

정부안은 2026년 현행 기준을 거쳐 2027년 중간 단계, 2028년 본격 시행으로 2년에 걸쳐 단계적으로 개편하는 일정을 두고 있습니다.

공식 원문

함께 읽기

계산 다음에 할 일

블로그 계산기는 정책안의 구조와 내 조건의 차이를 빠르게 확인하는 용도입니다. 실제 관심 아파트의 공시가격, 최근 실거래 흐름, 이사 시점, 금리와 함께 비교하려면 아파트 인사이트에서 관심 단지와 조건을 확인해볼 수 있습니다.

계산 결과는 의사결정 참고용 정보이며, 실제 신고·납부 전에는 최신 법령과 공식 안내를 다시 확인해야 합니다.

부동산과 아파트 통계를 처음 읽는 순서

· 약 6분
Alvin Hong
Alvin Hong
Senior Software Engineer

부동산과 아파트 통계는 숫자를 많이 보는 것보다 같은 기준으로 비교하는 순서를 정하는 일이 먼저입니다. 최근 실거래가 한 건, 월간 평균, 과거 차트, 미래 예상 범위는 서로 다른 질문에 답하기 때문입니다. 이 글은 특정 지역의 매수·매도를 권하는 글이 아니라, 관심 단지의 자료를 처음 확인할 때 어떤 순서로 숫자와 조건을 맞춰야 하는지 정리한 입문 안내서입니다.

아파트 가격을 볼 때 현재 거래가·과거 이력·예상 범위를 나눠야 하는 이유

· 약 4분
Alvin Hong
Alvin Hong
Senior Software Engineer

아파트 가격을 검색하면 실거래가, 호가, 과거 최고가, 예상 가격이 한 화면에 섞여 나오는 경우가 많습니다. 하지만 이 네 가지 숫자는 서로 다른 질문에 답합니다.

  • 지금 실제로 계약된 가격은 얼마인가
  • 같은 단지가 과거에 어떤 흐름을 보였는가
  • 앞으로 가능한 가격 경로는 어느 정도의 폭을 가지는가

이 질문을 한 숫자로 합치면 시세를 빠르게 보는 것 같지만, 오히려 중요한 차이를 놓치기 쉽습니다.

먼저 세 가지 층을 분리해 보기

아파트 가격을 읽는 세 겹의 기준
과거 거래, 현재 기준점, 미래 예상 범위를 나누어 보는 개념도과거에는 여러 거래가 쌓이고, 현재 시점에는 기준점이 있으며, 앞으로는 하나의 선이 아니라 범위로 표시됩니다.과거 거래현재앞으로여러 거래의 흐름예상 범위현재 기준점가격 수준시간
과거 실거래 흐름현재 기준점미래 예상 범위

개념도입니다. 실제 단지 분석에서는 기준일·면적·거래 표본을 따로 확인해야 합니다.

위 차트는 특정 단지의 실제 데이터가 아니라 가격 정보를 읽는 순서를 나타낸 개념도입니다. 과거 거래는 이미 관측된 기록이고, 현재 거래는 기준일의 앵커이며, 미래는 여러 조건에 따라 달라질 수 있는 범위입니다.

1. 최근 실거래가는 ‘현재 확인된 거래’다

국토교통부 실거래가 공개시스템의 아파트 거래는 계약일을 기준으로 조회합니다. 신고와 공개 사이에는 시간이 생길 수 있고, 계약이 해제되거나 정정될 수도 있으므로 조회 시점의 데이터 상태도 함께 봐야 합니다.

실거래가를 볼 때는 가격만 복사하지 말고 다음 조건을 같이 기록하는 편이 좋습니다.

  • 전용면적과 평형
  • 거래 시점과 층
  • 동일 단지 안의 동·향·뷰 차이
  • 직전 거래와의 시간 간격
  • 거래량이 충분한지 여부

같은 단지라도 면적과 층이 다르면 가격을 그대로 비교하기 어렵습니다. 특히 거래가 드문 단지는 최근 한 건이 단지 전체의 대표 가격처럼 보일 수 있습니다.

2. 과거 이력은 방향보다 맥락을 보여준다

과거 가격 흐름은 “얼마나 올랐나”만 계산하는 자료가 아닙니다. 다음과 같은 질문을 확인하는 자료입니다.

  • 가격 변화가 한두 건의 거래 때문인지, 여러 달 이어진 흐름인지
  • 상승과 하락이 거래량 변화와 함께 나타났는지
  • 비슷한 면적의 거래가 반복적으로 확인되는지
  • 특정 시점의 정책·금리·공급 변화와 움직임이 겹치는지

과거 최고가와 현재 거래가를 비교하는 것도 도움이 되지만, 최고가를 회복해야 한다는 목표처럼 사용하면 안 됩니다. 최고가는 특정 시점의 거래 조건을 포함한 기록일 뿐, 미래 가격의 기준선이나 보장값이 아니기 때문입니다.

3. 미래는 한 줄보다 범위로 읽는다

미래 예상은 아직 관측되지 않은 구간입니다. 금리, 공급, 거래량, 정책, 지역별 수요가 달라지면 같은 단지도 다른 경로를 보일 수 있습니다.

따라서 “12개월 뒤 얼마인가요?”보다 다음 질문이 더 정확합니다.

  1. 현재 기준점은 어떤 거래와 기준일로 만들어졌는가
  2. 예상 범위의 아래쪽과 위쪽은 어떤 불확실성을 담고 있는가
  3. 기간이 길어질수록 범위가 넓어지는가
  4. 내 보유·거주·대출 조건을 넣으면 해석이 달라지는가

미래 가격을 범위로 읽는 방법은 하나의 숫자보다 범위로 봐야 하는 이유에서 더 자세히 설명했습니다.

아파트 시세를 읽는 실전 순서

첫째, 기준일을 고정한다

“최근”이라는 말만으로는 부족합니다. 조회 기준일과 마지막 거래일을 함께 적어야 오래된 정보와 최신 정보를 구분할 수 있습니다.

둘째, 비교 조건을 맞춘다

전용면적·층·거래 유형이 다른 가격을 한 선에 올리면 차트가 정교해 보여도 해석은 흔들립니다. 같은 조건을 먼저 모은 뒤, 다른 조건은 별도 표본으로 분리합니다.

셋째, 현재·과거·미래를 다른 색과 영역으로 본다

과거는 선, 현재는 기준점, 미래는 띠나 범위로 표시하면 숫자의 성격이 한눈에 드러납니다. 세 값을 한 선으로 이어 그리면 예상과 사실이 같은 확실성을 가진 것처럼 보일 수 있습니다.

넷째, 숫자와 함께 데이터의 빈틈을 적는다

거래가 적은 단지, 면적이 섞인 표본, 해제 거래가 포함된 경우에는 “가격이 얼마다”보다 “이 가격을 얼마나 확실하게 비교할 수 있는가”가 먼저입니다.

참고 자료와 다음 읽을거리

과거 거래 흐름을 확인한 다음 내 관심 단지와 보유 조건까지 함께 비교하고 싶다면 공개 아파트 분석 도구에서 같은 질문을 직접 적용해볼 수 있습니다.

실거래가와 예상 범위는 기준일·표본·조건에 따라 달라질 수 있습니다. 이 글은 투자 권유나 매수·매도 추천이 아니며, 최종 판단과 책임은 이용자에게 있습니다.

미래 아파트 가격을 하나의 숫자로 단정하면 위험한 이유

· 약 4분
Alvin Hong
Alvin Hong
Senior Software Engineer

“그래서 1년 뒤 아파트 가격은 얼마인가요?”라는 질문은 자연스럽지만, 답을 하나의 숫자로만 받으면 오히려 중요한 정보를 잃을 수 있습니다.

가격 전망에는 기준일, 거래 표본, 금리, 공급, 정책, 지역별 수요가 함께 들어갑니다. 이 조건들이 조금만 달라져도 결과가 달라질 수 있기 때문에, 좋은 전망은 숫자를 단정하기보다 가능한 범위와 그 범위를 만든 조건을 보여줍니다.

이 글의 초점은 “왜 미래 가격을 범위로 봐야 하는가”라는 개념 설명입니다. 실제 결과 화면에 표시된 아래·가운데·위 값을 어떤 순서로 읽을지는 아파트 예상 범위의 아래·가운데·위 값을 해석하는 법에서 별도로 다룹니다.

하나의 숫자보다 범위가 필요한 이유

하나의 예측값보다 범위가 알려주는 것
같은 출발점에서 보수적, 기준, 낙관적 범위가 달라지는 개념도세 가지 가정은 같은 현재 기준점에서 출발하지만 시간이 멀어질수록 가능한 결과의 폭이 달라집니다.현재먼 미래보수적기준낙관적시간이 멀어질수록 가정의 차이가 범위에 반영됨가능한 가격 경로예측 기간
가능한 결과의 폭범위 안의 중심 추정

범위는 보장이 아니라 불확실성을 보여주는 참고 정보입니다.

위 차트는 특정 지역이나 단지의 실제 전망이 아니라, 시간이 멀어질수록 불확실성이 커지는 구조를 보여주는 개념도입니다. 세 경로가 모두 같은 현재 기준점에서 시작하더라도 미래로 갈수록 조건의 차이가 결과의 폭으로 나타납니다.

중심 추정값은 결론이 아니라 기준점이다

중심에 있는 추정값은 여러 가능성 중 하나를 읽기 위한 기준입니다. 그 숫자만 보고 “이 가격에 도달한다”고 해석하면 안 됩니다.

중심 추정값을 볼 때는 다음을 확인하세요.

  • 기준일이 언제인가
  • 마지막으로 반영된 거래는 언제인가
  • 대상 면적과 비교 표본이 일치하는가
  • 예상 기간이 6개월인지 12개월인지 18개월인지
  • 금리와 공급 같은 조건이 고정되어 있는가

기간이 길어질수록 확인해야 할 조건이 늘어나므로, 짧은 기간의 좁은 범위와 긴 기간의 넓은 범위를 같은 의미로 비교하면 안 됩니다.

범위의 아래쪽과 위쪽은 무엇을 뜻할까

범위의 아래쪽은 반드시 하락한다는 뜻이 아닙니다. 거래가 줄거나 자금 부담이 커지는 등 불리한 조건이 이어질 때 가능한 경로를 보여주는 참고선에 가깝습니다.

범위의 위쪽도 반드시 도달한다는 뜻이 아닙니다. 수요가 유지되고 거래 환경이 개선되는 경우처럼 다른 조건에서 가능한 경로를 보여줍니다.

따라서 범위를 읽을 때는 “아래냐 위냐”보다 다음을 묻는 편이 낫습니다.

  1. 두 경계를 벌어지게 만든 조건은 무엇인가
  2. 지금 확인된 자료가 어느 구간까지 충분한가
  3. 내 아파트의 거래 표본이 같은 조건을 대표하는가
  4. 새 거래나 정책 변화가 생기면 범위가 다시 계산되는가

범위가 넓다고 분석이 무의미한 것은 아니다

범위가 넓다는 것은 현재 시점에서 모르는 것이 많다는 뜻이지, 아무 정보도 없다는 뜻은 아닙니다. 오히려 아래와 같은 판단에 도움이 됩니다.

  • 단기와 장기의 불확실성 차이
  • 금리 변화에 민감한 자금 계획인지 여부
  • 거래가 부족해 추가 확인이 필요한 단지인지 여부
  • 특정 조건을 바꿨을 때 결과가 얼마나 움직이는지

반대로 범위가 지나치게 좁은데 기준일·거래 표본·조건 설명이 없다면, 숫자가 정교해 보이는 것과 실제로 확실한 것은 구분해야 합니다.

현재 가격과 미래 범위를 한 차트에 놓는 법

아파트 가격 차트를 만들 때는 다음 세 가지 표현을 분리하는 것이 좋습니다.

표현보여주는 것읽을 때 주의할 점
현재 기준점 또는 최근 대표 거래어떤 조건의 거래인지 확인
과거 거래 흐름 또는 중심 경로사실과 전망의 경계 확인
가능한 가격 범위보장값이 아닌 불확실성 표시

이렇게 그리면 독자는 “이미 발생한 가격”과 “앞으로 가능한 경로”를 같은 확실성으로 받아들이지 않게 됩니다.

전망을 읽기 전 체크리스트

  • 가격 기준이 실거래가인지 호가인지 확인하기
  • 기준일과 마지막 데이터 시점 확인하기
  • 면적·층·거래 유형이 같은지 확인하기
  • 기간별 범위를 따로 비교하기
  • 금리·공급·정책 조건이 바뀌었는지 확인하기
  • 가격 범위를 매수·매도 추천으로 바꾸어 해석하지 않기

참고 자료

앞서 읽은 현재 거래가·과거 이력·예상 범위를 나눠 보는 방법과 함께 보면 차트의 각 선과 띠가 어떤 역할을 하는지 더 쉽게 이해할 수 있습니다. 공개된 예측 개념을 더 자세히 보고 싶다면 미래가격 예측 공식 가이드기술 백서를 참고할 수 있습니다. 실제 결과 카드의 하단·중앙·상단 값을 확인하려면 아파트 예상 범위 화면 읽기로 이어서 읽어 보세요.

내 관심 아파트의 기준일·거래 흐름·기간별 조건을 직접 비교해보고 싶다면 공개 아파트 분석 도구에서 같은 방식으로 조건을 확인해볼 수 있습니다.

가격 전망과 범위는 참고용 분석이며 실제 가격·거래 가능성·수익을 보장하지 않습니다. 이 글은 투자 자문이나 매수·매도 추천이 아닙니다.

주택담보대출 금리와 아파트 가격의 상관관계: 금리 인하가 집값에 미치는 영향

· 약 5분
Alvin Hong
Alvin Hong
Senior Software Engineer

금리가 오르면 집값이 내리고, 금리가 내리면 집값이 오른다는 설명은 이해하기 쉽습니다. 하지만 실제 아파트 시장에서는 금리 변화와 실거래가 움직임 사이에 시간이 생깁니다.

금리는 먼저 대출을 이용하는 가계의 월 부담과 구매 가능한 가격대를 바꾸고, 그 다음 거래 속도와 협상 조건을 거쳐 가격에 영향을 줍니다.

금리에서 아파트 가격까지는 여러 단계를 거친다

금리 변화가 아파트 가격에 닿는 경로
금리 변화 → 가계 현금흐름 → 거래 조건 → 실제 가격으로 이어지는 시간차가 있습니다.

금리별 월 상환액과 총 이자 부담 직접 비교하기

💡 주택담보대출 금리별 월 상환액 비교기
금리가 1%p 변할 때 매월 지출하는 원리금과 총 이자 부담이 얼마나 달라지는지 직접 확인해보세요. (원리금 균등상환 기준)
기준 금리 4.5% 적용 시
253만원
30년 총 이자: 4억 1,203만원
비교 금리 3.5% 적용 시
225만원
30년 총 이자: 3억 828만원
금리가 1.0%p 낮아지면:매달 29만원 절감 (30년 누적 총 1억 375만원 절약)

* 거치기간 없는 원리금균등분할상환 기준 단순 계산이며, 실제 은행 대출 취급 시 중도상환수수료, 우대금리 조건, 거치 여부 등에 따라 달라질 수 있습니다.

이 흐름은 모든 지역과 모든 가구에 같은 크기로 적용되는 공식이 아닙니다. 기존 대출의 고정·변동 여부, 대출 만기, 소득, 보유 현금, 전세 상황에 따라 체감 부담이 달라집니다.

1. 시장 금리와 내 적용 금리는 다르다

한국은행 금융·경제 스냅샷경제통계시스템에서 확인하는 대출금리는 여러 금융기관의 평균을 보여주는 통계입니다.

이 평균은 시장의 방향을 읽는 데 유용하지만, 개인이 실제로 적용받는 금리와는 다를 수 있습니다. 신용 조건, 담보 가치, 대출 기간, 고정·변동 선택, 우대 조건에 따라 달라지기 때문입니다.

따라서 기사를 읽을 때는 “평균 금리가 몇 퍼센트인가”에서 멈추지 말고 다음 두 값을 분리해야 합니다.

  • 시장을 읽는 참고 금리
  • 내 대출 계약에 실제 적용되는 금리

2. 월 상환 부담이 먼저 바뀐다

같은 금액을 빌려도 금리와 만기가 바뀌면 월 납입액과 전체 이자 부담이 달라집니다. 원리금균등상환인지, 원금균등상환인지, 만기일시상환인지에 따라서도 현금흐름은 달라집니다.

그래서 아파트 가격을 금리와 연결할 때는 “금리 1%포인트 변화 = 집값 몇 퍼센트 변화”처럼 바로 환산하기보다 다음 순서가 현실적입니다.

  1. 대출 잔액과 남은 기간 확인
  2. 고정·변동 여부 확인
  3. 월 상환액이 소득과 생활비에서 차지하는 비중 확인
  4. 금리가 바뀌어도 유지할 수 있는 현금흐름인지 확인

3. 구매 가능한 가격대가 달라진다

월 상환 부담이 커지면 같은 소득을 가진 가구가 감당할 수 있는 대출 규모가 줄어들 수 있습니다. 반대로 부담이 줄면 더 높은 가격대까지 검토할 여지가 생깁니다.

하지만 이것이 곧바로 모든 아파트 가격의 등락으로 이어지지는 않습니다. 지역별 공급, 전세 가격, 보유자의 매도 필요성, 현금 구매자 비중이 함께 작용하기 때문입니다.

금리 기사를 아파트 시세에 연결할 때는 지역별 거래량과 거래 간격을 같이 보는 것이 좋습니다. 가격이 유지되어 보여도 거래가 크게 줄었다면 시장의 조정이 거래량과 협상 과정에서 먼저 나타났을 수 있습니다.

4. 가격보다 거래 속도와 협상력이 먼저 움직일 수 있다

금리 변화 직후에 모든 계약 가격이 같은 방향으로 이동하지는 않습니다. 먼저 매수자는 관망하고, 매도자는 가격을 유지하려 하며, 실제 계약까지 걸리는 시간이 길어질 수 있습니다.

이때 확인할 지표는 다음과 같습니다.

  • 월별 거래 건수
  • 최근 거래 사이의 간격
  • 같은 면적의 거래가 반복되는지 여부
  • 호가와 실제 계약 가격의 차이
  • 전세 가격과 매매 가격의 동반 움직임

가격만 보면 변화가 늦게 보일 수 있으므로, 거래량과 거래 간격을 함께 차트에 그리는 편이 좋습니다.

금리와 아파트 가격을 함께 읽는 체크리스트

질문확인할 자료해석의 주의점
금리가 변했나한국은행 평균 금리·기준금리개인 적용 금리와 다름
내 부담이 변했나대출 잔액·만기·상환 방식가구별 차이가 큼
거래가 반응했나거래량·거래 간격가격보다 먼저 움직일 수 있음
가격이 반응했나같은 면적·층의 실거래표본이 적으면 과대해석 위험
다른 조건은 같은가공급·전세·정책·지역 수요금리 하나로 설명하지 않기

자주 묻는 질문 (FAQ)

Q. 기준금리가 인하되면 아파트 가격은 바로 반등하나요?

기준금리가 인하되더라도 은행의 대출 가산금리 정책, 스트레스 DSR 규제 강화, 기존 주택 매물 소화 과정 등을 거치므로 시장 가격에 반영되기까지는 보통 3개월에서 6개월 이상의 시차가 발생합니다.

Q. 주택담보대출 금리가 1%p 변할 때 월 상환액 부담은 얼마나 차이 나나요?

대출 5억원 30년 만기 원리금 균등상환 기준, 금리가 1%p(예: 4.5%에서 3.5%) 낮아지면 매달 납부하는 원리금이 약 29만원 줄어들며, 30년간 누적 총 이자는 1억원 이상 절약됩니다.

Q. 스트레스 DSR이란 무엇이며 대출 한도에 어떤 영향을 주나요?

향후 잠재적 금리 인상 위험을 감안해 실제 대출 금리에 가산금리(스트레스 금리)를 얹어 연간 원리금 상환액을 산정하는 규제입니다. 금리 자체가 오르지 않아도 계산상 상환 부담이 커져 실제 빌릴 수 있는 총 대출 한도가 축소됩니다.

참고 자료

금리와 가격을 기간별로 비교하는 방법은 현재 거래가·과거 이력·예상 범위를 나눠 보는 글에서 이어서 확인할 수 있습니다. 금리 조건을 바꿨을 때 가능한 가격 경로를 어떻게 읽는지는 공식 가이드의 미래가격 예측 설명도 참고할 만합니다.

내 관심 단지의 최근 거래와 금리 조건을 함께 놓고 비교해보고 싶다면 공개 아파트 분석 도구에서 확인할 수 있습니다.

금리와 주택 가격의 관계는 지역·가구·대출 상품·공급 조건에 따라 달라집니다. 이 글은 금융상품 가입이나 대출 실행을 권유하지 않으며, 최종 판단 전 금융기관의 최신 조건을 확인해야 합니다.

아파트 교통 호재 분석법: 발표·착공·개통 단계별 집값 반영 시점

· 약 5분
Alvin Hong
Alvin Hong
Senior Software Engineer

“새 노선이 들어온다”는 한 문장만으로 아파트 가격을 판단하기는 어렵습니다. 같은 교통 사업이라도 발표 단계인지, 검토가 끝났는지, 공사가 시작됐는지, 실제로 이용할 수 있는지에 따라 확인해야 할 내용이 완전히 달라집니다.

교통 호재는 진행 단계가 핵심이다

교통 호재는 단계별로 다시 확인해야 합니다

발표만으로 개통 시점이나 실제 통행 편의를 확정할 수 없습니다. 단계와 공식 문서의 기준일을 함께 확인하세요.

국토교통부 철도산업 사업현황 공공데이터는 사업 추진 과정에서 조사·설계·고시·계획 수립·착공 등 여러 이력이 발생할 수 있음을 보여줍니다. 실제 사업마다 절차와 명칭은 다를 수 있으므로, 차트는 공통적으로 확인하기 쉬운 읽기 순서로 이해하면 됩니다.

1. 발표: 방향과 필요성을 알리는 단계

발표는 사업이 중요하다는 신호지만, 노선·역 위치·사업비·개통 시점이 모두 확정됐다는 뜻은 아닙니다.

이 단계에서 확인할 질문은 다음과 같습니다.

  • 어떤 기관이 발표했는가
  • 발표 자료에 사업 대상과 범위가 명확히 적혀 있는가
  • 예산·재원·추진 주체가 함께 언급됐는가
  • 목표 일정인지 확정 일정인지 구분되어 있는가

기사 제목만 저장하기보다 발표 기관의 원문과 기준일을 먼저 저장하는 편이 안전합니다.

2. 검토·타당성: 사업을 추진할 근거를 확인하는 단계

수요, 비용, 기술적 가능성, 주변 사업과의 연계 등을 검토하는 단계입니다. 검토 결과에 따라 사업 범위와 일정이 달라질 수 있습니다.

아파트 가격을 읽을 때는 “검토 중”이라는 표현을 “공사가 결정됨”으로 바꾸어 쓰지 않아야 합니다. 통과 여부와 조건, 이후 계획 수립 여부를 별도로 확인해야 합니다.

3. 계획·설계: 노선과 이용 조건이 구체화되는 단계

기본계획, 실시설계, 사업계획 승인 같은 문서가 나오면 노선·역·환승·공사 범위를 더 구체적으로 확인할 수 있습니다. 그래도 설계와 협의 과정에서 세부 내용이 바뀔 수 있습니다.

이 단계에서는 단순히 “역이 생긴다”가 아니라 다음을 지도에 표시해보세요.

  • 단지에서 역까지 실제 보행 동선
  • 환승 횟수와 주요 업무지구까지의 이동 시간
  • 역 출입구와 생활권의 위치
  • 공사 기간 동안의 우회·소음·교통 영향

4. 착공: 기대와 공사가 분리되는 단계

착공은 사업이 현장 단계로 넘어갔다는 강한 신호입니다. 하지만 착공했다고 바로 통행이 시작되는 것은 아닙니다. 공사 기간, 공정률, 개통 목표, 추가 공사 여부를 계속 확인해야 합니다.

특히 교통 호재를 가격 차트에 반영할 때는 착공일 하나만 표시하지 말고, 착공 이후 실제 공정과 개통 일정의 변동도 별도로 기록하는 것이 좋습니다.

5. 개통: 실제 통행 편의를 확인하는 단계

개통은 계획이 실제 이용 가능한 교통 서비스로 바뀌는 시점입니다. 이때부터는 발표 자료가 아닌 실제 이동 시간, 배차 간격, 환승 편의, 혼잡도, 이용 요금을 확인할 수 있습니다.

역이 개통되어도 모든 단지가 같은 혜택을 받는 것은 아닙니다. 도보권인지, 버스 환승이 필요한지, 출근 시간대에 실제로 편리한지에 따라 체감 편의는 달라집니다.

교통 호재를 아파트 가격과 연결하는 순서

  1. 사업 단계와 기준일을 먼저 적습니다.
  2. 공식 문서에서 노선·역·일정을 확인합니다.
  3. 단지에서 역까지의 실제 동선을 지도에서 봅니다.
  4. 개통 전에는 기대 요인과 일정 위험을 분리합니다.
  5. 개통 후에는 실제 통행 시간과 생활 편의를 다시 확인합니다.

자주 묻는 질문 (FAQ)

Q. 교통 호재는 발표, 착공, 개통 중 어느 시점에 집값에 가장 크게 반영되나요?

통상적으로 초기 계획 발표 시 기대감으로 1차 선반영이 일어나고, 사업 확정 후 실제 착공 시 2차 상승, 그리고 완공 및 개통으로 실제 통행 편의가 입증될 때 3차 시세 형성이 이루어집니다.

Q. 단순 계획 발표 단계의 교통 호재를 볼 때 주의할 점은 무엇인가요?

발표 단계는 예비타당성조사, 재원 마련, 기본설계 등 거쳐야 할 관문이 많아 사업 지연이나 노선 변경, 무산 위험이 높으므로 목표 일정을 확정된 사실로 오해하지 말아야 합니다.

Q. 역세권 아파트라도 개통 후 가격이 오르지 않는 경우가 있나요?

착공 이전 단계에서 기대감이 과도하게 선반영되어 이미 높은 시세가 형성되었거나, 배차 간격이 길고 출퇴근 핵심 업무지구로의 직결성이 떨어지는 노선일 경우 개통 후 추가 상승 폭이 제한될 수 있습니다.

참고 자료

교통 호재 하나만으로 아파트 가격이 정해지는 것은 아닙니다. 거래량, 공급, 전세 흐름, 직주근접, 생활 인프라를 함께 봐야 같은 지역 안에서 단지별 차이를 설명할 수 있습니다.

아파트 가격을 현재 거래·과거 흐름·미래 범위로 나누어 읽는 방법은 아파트 가격의 세 가지 기준에서 이어집니다. 공개 분석의 기본 개념과 데이터 해석 원칙은 공식 가이드 모음에서 확인할 수 있습니다.

교통과 거래 흐름을 내 관심 단지에 함께 적용해보고 싶다면 공개 아파트 분석 도구에서 직접 비교할 수 있습니다.

교통 사업의 일정과 범위는 공식 발표·고시·설계·공사 과정에서 달라질 수 있습니다. 이 글은 특정 지역이나 단지의 가격 상승을 보장하거나 매수를 권유하지 않습니다.

크로스플랫폼 앱 개발을 위한 플러터 소개

· 약 10분
Alvin Hong
Alvin Hong
Senior Software Engineer

플러터란?

플러터는 구글이 출시한 오픈소스 크로스플랫폼 GUI 애플리케이션 프레임워크입니다. 안드로이드, iOS, 윈도우즈, 리눅스 및 웹 애플리케이션과 구글 퓨시아 앱의 주된 소스코드로 사용됩니다. 2.0 버전부터 웹 애플리케이션을 지원했으며, 3.0 버전에서는 맥OS와 윈도우즈 애플리케이션도 지원하게 되었습니다.

플러터 기반의 대표적인 서비스

우리가 알만한 몇 가지 서비스를 소개하겠습니다. 플러터 공식 홈페이지에서 제공되는 각 서비스의 성공 지표는 다음과 같습니다. 네이버 지식iN에 대한 설명은 다음 장에서 계속됩니다.

  • 네이버 지식iN
  • 구글 페이
    • 엔지니어의 노력 70% 감소, 코드 라인 수 35% 감소
  • 텐센트
    • 개발 시간이 33% 감소, 앱 코드에서 플러터의 비중은 90%
  • eBay 모터스
    • 네이티브보다 개발 속도가 2배 빠르다고 생각하는 개발자 비중이 70%
  • BMW

플러터 구조 및 동작 원리

플러터는 세 가지 계층으로 구성됩니다. 하드웨어와 직접 통신하는 임베더 계층, C++로 작성된 엔진 계층, 그리고 개발자들이 주로 사용하는 프레임워크 계층입니다. 임베더 계층은 6개 플랫폼의 네이티브 플랫폼과 통신하며 운영체제 기능을 모듈화합니다. 엔진 계층은 플러터 코어 API, 스키아 그래픽 엔진, 파일 시스템, 네트워크 기능 등을 정의합니다.

프레임워크 계층에는 플러터를 사용하는 데 필수적인 위젯, 애니메이션, 매터리얼 디자인 패키지, 쿠퍼티노 디자인 패키지 등이 포함됩니다. 이렇게 세 가지 계층으로 나뉘고 잘 모듈화된 아키텍처 덕분에 플러터는 다양한 플랫폼을 쉽게 지원하며, 일관된 API 및 개발 경험을 제공합니다.

image-1

플러터는 스키아 엔진을 지원하는 모든 플랫폼에서 실행될 수 있도록 구현됩니다. 플러터 팀은 iOS와 안드로이드 앱뿐만 아니라 윈도우, 리눅스, 맥OS 애플리케이션, 심지어 웹사이트까지 플러터 코드로 배포할 수 있도록 했습니다. 플러터를 사용하면 한 번에 6가지 플랫폼에 애플리케이션을 배포할 수 있습니다.

플러터가 스키아 엔진을 사용할 때의 장점은 무엇일까요? 대부분의 크로스플랫폼 앱 개발 프레임워크들은 웹뷰를 사용하거나 각 플랫폼의 UI 라이브러리를 사용합니다. 하지만 플러터는 웹뷰를 사용하지 않고 직접 스키아 엔진을 이용하여 화면에 UI를 그립니다.

기존의 플랫폼에서 제공되는 UI를 모두 버리고 자체적으로 UI를 렌더링하기 때문에 iOS에서 매터리얼 디자인과 ripple 애니메이션을 볼 수 있고, 안드로이드에서 쿠퍼티노 디자인을 사용할 수 있습니다.

플러터는 화면 전체를 2D 그래픽 API로 fillRect하고, drawText와 drawImage를 사용하여 앱을 만드는 것과 같은 방식으로 스키아 기반으로 렌더링해줍니다. 이는 웹 개발에서 HTML을 모두 무시하고 전체를 플래시나 캔버스로 만드는 것과 유사합니다.

예를 들어, 플러터의 대표적인 경쟁 프레임워크인 리액트 네이티브는 자바스크립트 브릿지를 통해 플랫폼과 통신합니다. 또한 플랫폼의 UI(OEM 위젯)를 그대로 사용합니다. 그래서 플랫폼과 리액트 네이티브 간의 통신에는 상당한 리소스 비용이 듭니다. 하지만 플러터는 위젯을 스키아 엔진에 직접 그려내고 필요한 제스처 및 이벤트를 브릿지를 통하지 않고 실행하기 때문에 리액트 네이티브에 비해 상당히 빠른 성능을 자랑합니다.

참고로 플러터 팀은 초당 60프레임을 목표로 많은 노력을 기울인다고 합니다.

image-2

다트 언어를 채택한 이유

다트는 2011년에 구글이 개발한 클라이언트-사이드 개발 언어입니다. 처음에는 자바스크립트를 대체하기 위한 언어로 소개되었으며, 실제로 처음 제공한 트랜스 컴파일 결과물도 자바스크립트였습니다. 다트는 JIT(Just-In-Time) 컴파일을 통해 VM 위에서 동작하는 방식과 AOT(Ahead-Of-Time) 컴파일을 통해 런타임에서 바로 동작하는 방식을 모두 지원합니다.

JIT 컴파일은 인터프리터처럼 실행 전에 코드를 컴파일하지 않아도 되기 때문에, 코드 수정 시 발생하는 빌드 시간을 줄여 개발자들이 더 편리하게 개발할 수 있는 장점이 있습니다. 그러나 VM 위에서 동작하기 때문에 대부분의 코드가 네이티브 플랫폼에 비해 성능상 느리다는 단점이 있습니다. 그러나 다트는 AOT 컴파일도 지원하기 때문에 실제 배포 시 AOT 컴파일을 통해 런타임에서 바로 동작하는 코드를 생성할 수 있습니다.

AOT 컴파일은 다트 2버전이 나오면서 추가된 기능인데, 아마도 플러터 팀의 요청이 있었을 것이라고 생각합니다.

image-3

혹시 다른 언어도 다트처럼 JIT와 AOT 컴파일러를 둘다 사용하는지 궁금해서 검색을 해봤는데, 다트처럼 개발 단계와 릴리즈 단계에서 각각 다른 컴파일 방식을 사용하는 언어는 없었습니다.

  1. C# / .NET: .NET Core와 .NET 프레임워크는 JIT 컴파일을 기본으로 하지만, .NET Native나 AOT 컴파일 옵션을 통해 AOT 컴파일도 가능합니다.
  2. Dart: Dart 언어는 플러터에서 주로 사용되며, AOT와 JIT 둘 다 지원합니다. 개발 중에는 JIT 컴파일을 사용하여 빠른 개발 사이클을 유지하고, 릴리즈 시에는 AOT 컴파일을 사용하여 최적의 성능을 달성합니다.
  3. JavaScript / TypeScript: 일반적으로 자바스크립트는 인터프리터 언어로 분류되며, JIT 컴파일이 많이 사용됩니다. 그러나 웹 어셈플리를 통해 AOT 컴파일도 가능합니다.
  4. Rust: 러스트는 기본적으로 AOT 컴파일을 사용하지만, JIT 컴파일을 가능하게 하는 라이브러리도 존재합니다.
  5. Go: Go 언어는 주로 AOT 컴파일을 사용하지만, 몇몇 특별한 상황에서는 JIT 컴파일을 사용하는 경우도 있습니다.

hot reload

플러터의 hot reload를 사용하면 개발 시간을 단축시키고 거의 즉시에 가까운 속도로 개발할 수 있습니다. 이 기능은 다트의 JIT 컴파일을 기반으로 하며, 다트가 JIT 컴파일을 지원하기 때문에 앱을 즉시 수정하고 실행할 수 있습니다.

제니퍼 화면 개발 중 웹팩 번들러에서 제공하는 hot reload를 사용합니다. 수정된 코드가 빌드되고 브라우저에 반영되는 과정에는 몇 초의 시간이 소요되어 답답한 경우가 종종 있습니다. 이는 제니퍼의 소스 코드 규모가 방대하고 웹팩을 그대로 사용하기 때문에 발생하는 현상일 수 있습니다. 물론 최근 Vercel에서 발표한 터보팩과 같은 번들러는 더 빠를 수도 있습니다.

네이버의 플러터 도입 과정

최근에 데이빗과 플러터 스터디를 진행하면서 모니터링 스터디 주제로 선정해야겠다는 생각을 했었습니다. 관련해서 검색해보는데, 네이버의 플러터 도입 과정을 블로그에 자세히 올린게 있어서 개인적으로 느낀 점이 많아 이렇게 소개해보려고 합니다.

먼저, 크로스플랫폼 도입을 검토하게 된 이유가 흥미로웠습니다. 네이버 정도되는 규모의 회사에서는 서비스 앱 개발을 어떤 프로세스로 진행하는지 어느 정도 파악할 수 있었습니다. 특히 디자인 단계에서의 어려움은 iOS와 안드로이드에서 모두 동일한 UI를 제공하려고 하더라도 구현하기 어려운 UI가 존재한다는 것이었습니다.

각 플랫폼마다 개발, 테스트, 배포를 진행하며, 플랫폼 상황에 따라 배포 일정이 달라질 수 있고, 서비스 상황에 따라 개발자 불균형 문제가 발생할 수 있다는 점입니다. 또한, 기획을 제외하고 디자인부터 별도의 프로세스로 진행되는 것이 인상 깊었습니다.

image-4

이와 같은 상황에서 최대한 개발 효율성을 높이고자 다양한 방법을 시도했는데, 과거 네이버 블로그 앱 개발팀에 있던 시절에는 아래와 같은 방법을 시도했다고 말합니다.

  • 기술 공유
  • 네이밍 컨벤션 맞추기
  • 라이브러리 개발

기술 공유의 경우에는 서로 다른 플랫폼 간에 도움을 주는 지식이 아니기 때문에 시간이 흐를수록 꾸준한 참여를 유지하기 어려웠으며, 플랫폼 별로 선호하는 네이밍 컨벤션이 다르고 개발 일정에 따라 매번 컨벤션을 맞추기 어렵다는 한계가 있었습니다.

또한, 팀 내에서 라이브러리 개발을 담당하는 인원이 필요하다는 문제가 있었고, 꾸준한 관리가 어려워서 서비스 별로 다른 스펙을 라이브러리로 구현하기도 어렵다는 문제도 있습니다.

다음은 플랫폼의 차이와 관련하여 비슷한 경험이 있는지 사내 모바일 개발자를 대상으로 설문 조사를 진행하여 다음과 같은 결과를 얻었습니다.

image-5

대다수 개발자들은 플랫폼에 특화된 스펙을 구현하는 것이 어려웠고, 개발자 불균형으로 인해 프로젝트 진행에 문제가 있었다는 것을 알 수 있습니다. 또한, 서비스 상황에 따라 크로스플랫폼이 필요하다고 생각하는 비율도 월등히 높았다고 언급합니다.

결국 네이버는 프로토타입 프로젝트도 진행해 보고, 개발자 불균형 문제를 겪으면서 더 효율적인 개발 방법은 없을까 고민한 결과, 팀에서 크로스플랫폼을 검토하기로 결정했습니다. 대부분의 팀원들은 크로스플랫폼에 대해 회의적인 시각을 가졌으며, 네이티브 방식으로 개발한 앱보다 실행 성능이 낮을 것으로 예상하여 검토를 시작했다고 합니다. 하지만 검토를 진행하면서 이 부분이 편견이었음을 알았으며, 지식iN 앱을 플러터 기반으로 개발하고 정식 서비스를 시작했습니다.

크로스플랫폼에 도전

1차 테스트로 일주일 동안 6명의 개발자가 플러터, 리액트 네이티브, 자마린(xamarin), SCADE 4개의 크로스플랫폼에 대한 성능과 생산성을 검토했습니다. 크로스플랫폼 도입을 위한 과정이 체계적이고, 많은 노력을 기울였기 때문에 크로스플랫폼 도입을 검토하는 사람들에게 많은 도움이 될 것으로 생각합니다.

table-1

평가 기준을 바탕으로 각 플랫폼을 비교한 결과, 플러터가 가장 좋은 평가를 받았습니다. 특히, 플러터의 성능은 팀에서 기대한 것보다 훨씬 우수하게 나왔습니다. 화면 동작에서는 네이티브 방식과 구분하기 어려울 정도의 성능을 보였다고 합니다.

네이버에서는 추가적인 검증을 위해 2차 테스트를 진행했는데, 플러터로 어떤 단계까지 구현이 가능한지 확인하기 위해 조금 더 난이도가 있는 앱을 과제로 삼았습니다. 약 2개월 동안 진행된 프로토타입 서비스를 플러터로 구현하기로 하고, iOS 개발자 4명과 안드로이드 개발자 3명이 약 2주 동안 테스트를 진행했습니다.

추가 기능을 테스트하기 위해 라이브러리, Google 지도, 웹뷰, 커스텀 UI 등을 구현하여 확인한 결과, iOS 개발자 6명과 안드로이드 개발자 6명이 2개월 동안 개발한 서비스를 2주 만에 유사하게 구현했습니다.

table-2

팀원들의 공통적인 의견은 각각 네이티브 방식으로 개발할 때보다 훨씬 수월했다는 점입니다. 사용성 확인을 위해 UI에 굉장히 집중한 프로토타입 서비스에서는 플러터가 네이티브 방식보다 훨씬 빠르고 편하게 UI를 구현할 수 있기 때문입니다. 특히 안드로이드 개발자들의 만족도가 높았다고 합니다.

다음은 2차 테스트를 마무리하고, 팀원들이 작성한 플러터에 대한 피드백을 요약한 내용입니다. 내용을 가볍게 살펴보시면 좋을 것 같습니다.

table-3

플러터 스터디를 하면서 느낀점

다트 문법이 자바나 코틀린이랑 비슷하기 때문에 플러터 개발은 고대(?) 유물인 자바 스윙이 떠오르긴 했었는데, 전혀 아니었습니다. 네이버 팀에서 플러터로 개발할 때 개발 기간이 짧아진 이유에 대해 다트 언어의 어렵지 않은 문법과 플러터의 선언형 UI 방식 때문이라고 결론을 내렸는데, 제 생각도 동일합니다.

선언형 UI 방식은 복잡한 UI를 작성할 때 이해하기에 더 직관적이기 때문에 유리합니다. 사실, 프론트엔드 개발자라면 익숙한 HTML이나 JSX, 뷰 템플릿 문법들은 모두 선언형으로 볼 수 있습니다.

아래 코드를 비교하면 명령형과 선언형의 차이를 쉽게 이해할 수 있습니다.

// Imperative style
b.setColor(red)
b.clearChildren()
ViewC c3 = new ViewC(...)
b.add(c3)

Win32에서 웹, Android 및 iOS에 이르는 프레임워크는 일반적으로 명령형 UI 프로그래밍 스타일을 사용합니다. 이 스타일은 여러분이 가장 익숙한 스타일일 수 있는데, UIView 또는 이와 동등한 기능을 갖춘 UI 엔티티를 수동으로 구성하고 나중에 UI가 변경되면 메서드와 설정자를 사용하여 변경하는 방식입니다.

// Declarative style
return ViewB(
color: red,
child: const ViewC(),
);

반면, 플러터는 개발자가 다양한 UI 상태 간 전환 방법을 프로그래밍해야 하는 부담을 덜어주기 위해 개발자가 현재 UI 상태를 설명하고 전환은 프레임워크에 맡길 수 있도록 합니다.

개발자 도구

플러터 2.0부터 개발자 도구가 지원되었는데, 직접 사용해보니 매우 편리했습니다. 앞에서 언급한 hot reload와 함께 개발자 도구는 개발 생산성을 크게 향상시킬 것으로 기대됩니다.

image-6

예제 소개

먼저, 웹툰 예제는 노마드코더의 클론 코딩 강의에서 다룬 내용을 따라서 구현한 것입니다. 플러터는 네이티브 앱 수준의 페이지 전환 효과를 쉽게 구현할 수 있도록 관련 API를 제공합니다. 강의 댓글 중에서 흥미로운 내용을 발견했는데, 리액트 네이티브로 동일한 기능을 구현하는 것은 매우 어렵다며, 플러터로는 정말 간단하게 구현할 수 있다는 점이 좋았다는 것이었습니다.

플러터는 iOS의 쿠퍼티노 디자인 패키지를 지원하지만 네이티브 앱만큼 완벽하지는 않습니다. 시간이 지남에 따라 네이티브 앱과의 디자인 격차는 더 벌어질 것으로 예상됩니다. 필요에 따라 플러터의 디자인 패키지에서 제공하지 않는 UI를 개발해야 할 수도 있습니다. 이런 경우, 개발자는 CustomPainter 클래스를 상속받아 직접 캔버스에 그릴 수 있습니다.

이렇게 구현한 클래스는 결국 플러터에서 제공되는 위젯들과 동일한 위젯으로 취급되기 때문에 기존의 위젯들과 함께 자연스럽게 사용할 수 있습니다. 제니퍼에서 캔버스를 활용하여 만든 컴포넌트들 중에는 기존의 마크업이나 스타일과 함께 사용되는 경우도 있지만, 서로 독립적인 부분도 있으며, 특히 이벤트를 구현할 때 고려해야 할 사항이 많습니다.

마지막으로 플러터와 관련된 검색 중에 토스 앱에 있는 3D 인터랙션을 플러터로 구현한 예제를 발견했습니다. 개인적으로 토스의 UX/UI가 매우 훌륭하다고 생각하는데, 일부 기능 중 하나를 플러터로 쉽게 구현한 것을 보고 플러터의 가능성을 높게 평가하게 되었습니다.

image-7

  1. 페이지 전환 예제 : 페이지 전환시 효과를 쉽게 구현할 수 있습니다. (데스크탑 브라우저에서는 이미지가 보이지 않음)
  2. 캔버스 그리기 예제 : 캔버스에 그라디언트 효과를 주고, 심볼(별모양)을 직접 그려서 무작위로 화면에 보여지는 배경 위젯입니다.
  3. 3D 인터랙션 예제 : 토스 앱의 상품권 추가시 3D 인터랙션을 구현한 예제입니다.

글을 마치며

플러터 스터디를 진행하고 모니터링 스터디 발표 자료를 준비하면서 몇 가지 결론을 내리게 되었습니다. 첫째로, 데스크탑과 모바일은 완전히 다른 기획과 사용자 경험이 필요하다는 것입니다. 모바일은 프론트엔드 영역이 아니라 플랫폼에 종속된 전혀 다른 분야로 생각하고 크게 고민하지 않았습니다. 사실 플랫폼이 iOS와 안드로이드로 크게 나뉘어져 있기 때문에 어느 한 쪽을 선택하는 것이 어려웠습니다. 플러터 덕분에 이러한 선택의 어려움을 해결하고, 본격적으로 모바일 UX에 대해 알아볼 수 있게 되었습니다.

두 번째로, 이건 지극히 개인적인 사정이긴 한데, 프레임워크의 발전과 ChatGPT의 등장으로 프론트엔드 개발자로서 성장의 한계를 느끼고 있던 시점에 플러터를 발견하여 데스크탑 웹을 넘어 여러 플랫폼으로 프론트엔드 역량을 확장해나가야겠다는 새로운 목표가 생겼습니다.

데스크탑과 모바일을 모두 고려한 서비스가 무조건 성공하는 것은 아니지만, 현재 성공한 서비스들을 살펴보면 둘 중 하나만 지원되는 서비스는 드물다고 생각됩니다. 네이버의 플러터 도입 검토 과정을 보면 알 수 있듯이, 보다 적은 인원으로 네이티브 수준의 애플리케이션을 개발할 수 있다는 것은 개발 인원이 적은 조직에서 충분히 고려해볼 만하다고 생각합니다.

참고 링크

RSC(React Server Components) 살펴보기

· 약 10분
Alvin Hong
Alvin Hong
Senior Software Engineer

개요

2020년 12월 React 팀은 서버 주도(Server-Driven) 멘탈 모델로써 모던 UX를 가능하게 하는 것을 목표로 하는 zero-bundle React 서버 컴포넌트를 시연했습니다. 이때 소개한 서버 컴포넌트는 서버 사이드 렌더링(SSR)과는 상당히 다르며 클라이언트 측 번들 크기를 매우 줄일 수 있다고 하였으며, 서버와 클라이언트(브라우저)가 React 애플리케이션을 서로 협력하여 렌더링 할 수 있게 됩니다.

그리고 2022년 10월 Next.js Conf에서 Next.js 13부터 React 서버 컴포넌트를 지원한다고 발표했습니다. 처음 서버 컴포넌트를 소개한 후, 시간이 꽤 지났음에도 불구하고, 아직도 실험적인 단계이긴 하지만 Next.js 기반으로 서버 컴포넌트를 구현해볼 수 있게 되었습니다. Next.js 관련해서는 데이빗이 작성한 문서를 참고하시면 됩니다.

SSR의 한계

오늘날 자바스크립트의 서버 사이드 렌더링(SSR)은 초기 페이지 로드 시간을 개선하기 위한 차선책입니다. 컴포넌트의 자바스크립트는 서버에서 HTML 문자열로 렌더링됩니다. HTML은 브라우저에게 전달되고 나타나며, 빠른 FCP(First Contentful Paint) 혹은 LCP(Largest Contentful Paint)를 가지게 됩니다.

하지만 Hydration 단계를 통해 인터렉션이 가능해진 엘리먼트를 위해서는 여전히 자바스크립트가 필요합니다. 서버 사이드 렌더링은 일반적으로 최초 페이지 로드를 위해 사용되기 때문에 Hydration 이후에는 추가적으로 쓰이지 않습니다.

클라이언트에서의 Hydration을 전혀 하지 않고, React와 SSR만 가지고 애플리케이션을 만들 수도 있지만 애플리케이션에서 인터렉션을 많이 해야 하는 경우에는 어쩔 수 없이 클라이언트 측으로 코드를 보내야 합니다. 서버 컴포넌트의 하이브리드 모델은 이 선택을 컴포넌트 기준으로 가능하도록 해줍니다.

React의 서버 컴포넌트를 활용하면 컴포넌트들을 정기적으로 다시 받아올 수 있습니다. 새로운 데이터가 있을 때 서버에서 애플리케이션의 컴포넌트들을 리-렌더링 할 수 있으므로 클라이언트 측에 전송해야 하는 코드량을 줄일 수 있습니다.

SSR은 서버에서 HTML을 생성하고 클라이언트로 전송하는 방식입니다. SSR은 초기 로딩 속도를 높일 수 있지만 RSC는 더 많은 기능을 제공합니다.

Hydration이란?

  1. 컴포넌트를 렌더링하고, 이벤트 핸들러를 연결하는 프로세스
  2. 서버 단에서 렌더링한 정적 컨텐츠와 번들링 된 JS 파일을 클라이언트에게 보낸 뒤, 클라이언트 단에서 HTML 코드와 React인 JS 코드를 서로 매칭 시키는 과정

RSC vs SSR

결론부터 말하자면 RSC는 SSR을 대체할 수 없습니다. SSR은 해당 페이지의 HTML 코드를 미리 빌드합니다. 이것은 SEO에 효과적이고, 사용자가 자바스크립트 코드를 다운받는 동안 해당 페이지의 내용을 미리 볼 수 있습니다. 즉, SSR은 해당 페이지 자체를 렌더링하는 것이고, 서버 컴포넌트는 각각의 컴포넌트마다 클라이언트 컴포넌트로 렌더링 할 것인지 서버 컴포넌트로 렌더링 할 것인지를 선택해야 합니다.

Next.js와 SSR의 차이점에 대해 Dan과 Lauren의 talk에서 언급한 내용을 정리해 보면:

  • 서버 컴포넌트의 코드는 클라이언트로 전달되지 않습니다. 하지만 서버 사이드 렌더링의 모든 컴포넌트의 코드는 자바스크립트 번들에 포함되어 클라이언트로 전송됩니다.
  • 서버 컴포넌트는 페이지 레벨에 상관없이 모든 컴포넌트에서 서버에 접근 가능합니다. 하지만 Next.js의 경우 가장 top level의 페이지에서만 getServerProps()나 getInitialProps()로 서버에 접근 가능합니다.
  • 서버 컴포넌트는 클라이언트 상태를 유지하며 re-fetch 될 수 있습니다. 서버 컴포넌트는 HTML이 아닌 특별한 형태로 컴포넌트를 전달하기 때문에 필요한 경우 포커스, 인풋 입력값 같은 클라이언트 상태를 유지하며 여러 번 데이터를 가져오고 리렌더링하여 전달할 수 있습니다. 하지만 SSR의 경우 HTML로 전달되기 때문에 새로운 re-fetch가 필요한 경우 HTML 전체를 다시 렌더링 해야 하며, 이로 인해 클라이언트 상태를 유지할 수 없습니다.

탄생 배경

React 팀은 다방면으로 성능 향상을 해왔으나 Data Fetching의 경우, 사용자와 개발자 경험 모두를 만족시킬 수있는 방법을 찾기가 어려웠습니다. React 컴포넌트의 비동기적 Data Fetching의 가장 큰 문제점은 클라이언트와 서버 간 요청의 High Latency와 연속된 클라이언트-서버 API 요청으로 발생하는 Waterfall이었습니다.

image-1

이와 같이 클라이언트 컴포넌트에서 비동기 Data Fetching은 클라이언트-서버의 Waterfall을 야기하고, 성능을 저하시키는 원인이 됩니다.

이를 위한 해결책으로 서버 컴포넌트가 탄생하게 되었으며, RSC는 용어 그대로 서버에서 동작하는 React 컴포넌트입니다. 서버 컴포넌트를 사용하면 컴포넌트 렌더링을 클라이언트가 아닌 서버에서 수행할 수 있습니다.

서버에서 렌더링을 수행하기 때문에 API를 통한 데이터 요청의 Latency를 줄일 수 있고, 클라이언트에서의 연속된 API 호출을 제거하여, 클라이언트-서버의 Waterfall을 막을 수 있습니다.

image-2

아쉽게도 서버 컴포넌트에서의 데이터 요청을 처리하여도 중첩된 컴포넌트에서의 여러 API 요청에 따른 네트워크 Waterfall은 여전히 존재합니다.

하지만 서버 컴포넌트는 서버에서 동작하고 렌더링 된다는 특성상 다양한 종류의 백엔드 리소스에 접근할수 있고, HTML이 아닌 ‘특별한’ 형태로 렌더링 되어 클라이언트에 전달되기 때문에 클라이언트로 전달되는 번들 사이즈 또한 감소시킬 수 있습니다.

서버 컴포넌트란?

React가 UI를 구축하는 방식을 바꾼 것과 유사하게, 서버와 클라이언트를 활용하는 하이브리드 애플리케이션을 구축하기 위한 새로운 사고 모델을 도입했습니다.

SPA의 경우처럼 전체 애플리케이션을 클라이언트 측에서 렌더링하는 대신, React는 이제 컴포넌트의 목적에 따라 렌더링할 위치를 선택할 수 있는 유연성을 제공합니다.

image-3

페이지를 더 작은 컴포넌트로 분할하면 대부분의 컴포넌트가 비대화형이며 서버에서 서버 컴포넌트로 렌더링 할 수 있음을 알 수 있습니다. 더 작은 인터랙티브 UI의 경우, 클라이언트 컴포넌트로 나타낼 수 있습니다. 이는 Next.js의 서버 우선 접근 방식과 일치합니다.

서버 컴포넌트의 특징을 정리하면 다음과 같습니다.

  • 자유로운 서버 리소스 접근 : 데이터베이스, 파일 시스템 등등
  • 제로 번들 사이즈 컴포넌트 : 서버 컴포넌트는 브라우저에 다운로드 되지 않고, 서버에서 미리 렌더링 된 정적 컨텐츠로 전달됨
  • 자동 코드 분할 : 서버 컴포넌트에서 Import 되는 모든 클라이언트 컴포넌트를 코드 분할 포인트로 간주하기 때문에 Lazy 로드가 필요하지 않음

클라이언트와 서버 컴포넌트 구성하기

서버에서 React는 결과를 클라이언트로 보내기 전에 모든 서버 컴포넌트를 렌더링 합니다. 그리고 클라이언트에서 React는 클라이언트 컴포넌트를 렌더링하고 서버 컴포넌트의 렌더링 결과에 슬롯을 생성하여 서버와 클라이언트에서 수행한 작업을 병합합니다.

클라이언트 컴포넌트는 코드 상단에 ‘use client’ 디렉티브를 명시해야 합니다. 그리고 서버 컴포넌트를 import 할 수 없습니다.

대신 클라이언트 컴포넌트를 디자인 할 때, React 프로퍼티를 사용하여 서버 컴포넌트의 “holes”를 표시할 수 있습니다. 서버 컴포넌트는 서버에서 렌더링되고, 클라이언트 컴포넌트가 클라이언트에서 렌더링되면 서버 컴포넌트의 렌더링 된 결과로 “hole”이 채워집니다.

일반적인 패턴은 React의 children 프로퍼티를 사용하여 “hole”을 만드는 것입니다.

'use client';

import { useState } from 'react';

export default function ExampleClientComponent({
children,
}: {
children: React.ReactNode;
}) {
const [count, setCount] = useState(0);

return (
<>
<button onClick={() => setCount(count + 1)}>{count}</button>

{children}
</>
);
}

<ExampleClientComponent>는 자식 컴포넌트가 무엇인지 전혀 알지 못합니다. 사실, 이 컴포넌트의 관점에서는 자식들이 결국 서버 컴포넌트의 결과에 의해 채워질 것이라는 사실조차 알지 못합니다.

// This pattern works:
// You can pass a Server Component as a child or prop of a
// Client Component.
import ExampleClientComponent from './example-client-component';
import ExampleServerComponent from './example-server-component';

// Pages in Next.js are Server Components by default
export default function Page() {
return (
<ExampleClientComponent>
<ExampleServerComponent />
</ExampleClientComponent>
);
}

그리고 서버 컴포넌트는 클라이언트 컴포넌트를 Import 할 수 있지만 서버에서 클라이언트 컴포넌트로 전달되는 프로퍼티는 직렬화가 가능해야 합니다. 즉, 함수나 날짜 등과 같은 값은 클라이언트 컴포넌트에 직접 전달할 수 없습니다.

다음은 클라이언트와 서버 컴포넌트의 특징을 정리한 표입니다.

특징서버클라이언트
데이터 가져오기OX
백엔드 리소스에 직접 액세스 (직접)OX
서버에 민감한 정보 보관 (액세스 토큰, API 키 등)OX
서버에 대한 대규모 종속성 유지 / 클라이언트 측 자바스크립트 감소OX
인터랙티브 및 이벤트 리스너 추가 (onClick, onChange 등)XO
상태 및 라이프사이클 효과 사용 (useState, useReducer, useEffect 등)XO
브라우저 전용 API 사용XO
상태, 효과 또는 브라우저 전용 API에 의존하는 사용자 지정 후크 사용XO
React 클래스 컴포넌트 사용XO

데모 살펴보기

데모 화면은 Postgres DB에 저장된 사용자 목록을 가져와서 테이블 형태로 보여줍니다. 캐시 처리를 위해 Redis에 사용자 목록을 10초간 보관합니다.

// lib/service.ts

import kv from "@vercel/kv";
import { sql } from "@vercel/postgres";

export interface User {
id: number;
name: string;
image: string;
email: string;
createdAt: Date;
}

export async function getUsers(cacheKey: string) {
const cachedData = await kv.get<User[]>(`users-${cacheKey}`);
if (cachedData === null) {
const data = await sql<User>`SELECT * FROM users`;
await kv.set(`users-${cacheKey}`, JSON.stringify(data.rows), { ex: 10, nx: true })
return data.rows;
} else {
return cachedData;
}
}
// app/api/route.ts

import { getUsers } from '@/lib/service';
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
return NextResponse.json({ users: await getUsers('client') });
}

아래는 클라이언트 컴포넌트로 구현된 테이블 컴포넌트입니다. 데이터를 가져오기 위해 /api/users를 호출하고, API 내부에는 앞에서 구현한 서비스 함수를 사용합니다.

// components/client-table.tsx

'use client'

import type { User } from '@/lib/service';
import { useState, useEffect } from 'react';
import ReloadButton from './reload-button'
import TableHead from './table-head';
import TableRow from '@/components/table-row';

export default function ClientTable() {
const [users, setUsers] = useState<User[]>([]);
const [duration, setDuration] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false);

const loadData = () => {
let startTime = Date.now();
setLoading(true);
fetch('/api/users')
.then((res) => res.json())
.then((data) => {
setUsers(data.users)
setDuration(Date.now() - startTime)
setLoading(false)
})
}

useEffect(() => {
loadData();
}, [])

return (
<div className="bg-white/30 p-12 shadow-xl ring-1 ring-gray-900/5 rounded-lg backdrop-blur-lg max-w-xl mx-auto w-full">
<TableHead userCount={users.length} duration={duration}>
<ReloadButton onClick={loadData} loading={loading} />
</TableHead>
<div className="divide-y divide-gray-900/5">
{users.map((user, index) => (
<TableRow key={index} user={user}></TableRow>
))}
</div>
</div>
)
}

클라이언트 컴포넌트와 달리 API 호출을 위한 코드는 생략하고, 앞에서 구현한 서비스 함수를 바로 사용할 수 있습니다.

// components/server-table.tsx

import { getUsers } from '@/lib/service';
import RefreshButton from './refresh-button'
import TableHead from './table-head';
import TableRow from './table-row';

export default async function ServerTable() {
const startTime = Date.now()
const users = await getUsers('server');
const duration = Date.now() - startTime

return (
<div className="bg-white/30 p-12 shadow-xl ring-1 ring-gray-900/5 rounded-lg backdrop-blur-lg max-w-xl mx-auto w-full">
<TableHead userCount={users.length} duration={duration}>
<RefreshButton />
</TableHead>
<div className="divide-y divide-gray-900/5">
{users.map((user, index) => (
<TableRow key={index} user={user}></TableRow>
))}
</div>
</div>
)
}

데모 화면과 소스 코드는 아래 링크를 통해 직접 확인할 수 있습니다.

글을 마치며

이번 스터디 발표 준비를 하면서 RSC에 대해 알아보고 이해하는 과정을 겪으면서 느꼈던 점은 언젠가 APM 에이전트 라인업에 RSC가 포함될 수도 있을 것 같다는 생각이 들었습니다.

지금처럼 프론트엔드와 백엔드 개발 영역의 구분이 명확하지 않았던 시절의 웹 개발을 했던 모습도 떠오릅니다. 물론 그때와 지금은 엄청난 차이가 있고, 자바스크립트는 웹 페이지의 인터랙티브 한 기능을 제공하기 위한 보조적인 역할만 했던 시기이기도 합니다.

RSC가 추구하는 방향성을 이해하려고 하다보니 문득 이런 생각이 들었습니다. 어쩌면 다시 옛날처럼 프론트엔드와 백엔드를 구분하지 않고 개발하는 시대가 올 수도 있겠구나. 다만, 과거와 달리 앞으로는 메인은 화면 개발이고, 서브로 렌더링 성능 개선을 위한 서버 개발을 해야하는 상황이 올 수도 있겠다는 생각을 했습니다. (프론트엔드 개발자 기준에서…)

앞으로 웹 생태계에 어떤 변화가 다가올지 알 수는 없지만 한가지 분명한 것은 RSC가 큰 영향을 줄 수 있을 것 같습니다. 그래서 꾸준한 관심과 기대를 가져볼만하다고 생각합니다.

참고 링크

문서를 읽고 이해하는 것보다 직접 구현해보는게 나을 것 같아서 이번에도 데모 개발에 시간을 많이 할애했습니다. 본문 내용의 대부분은 아래 문서를 인용한 것이니 참고하시길 바랍니다.

D3 Hierarchy 모듈로 데이터 핸들링하기

· 약 3분
Alvin Hong
Alvin Hong
Senior Software Engineer

children을 포함하는 계층 데이터

D3에서 사용할 데이터를 정의할 때, 부모-자식 관계를 정하기 위해서 children을 반드시 포함시켜야 합니다. children에 자식 노드를 추가하면서 계층 데이터 형태로 구성할 수 있습니다.

interface TreeData {
id: string;
children?: TreeData[];
}

const TREE_DATA: TreeData = {
id: 'Chaos',
children: [
{
id: 'Gaia',
children: [
{
id: 'Mountains',
},
{
id: 'Pontus',
},
{
id: 'Uranus',
},
],
},
{
id: 'Eros',
},
{
id: 'Erebus',
},
{
id: 'Tartarus',
},
],
};

기본적인 Hierarchy 객체 생성하기

hierarchy 함수를 호출하면 D3에서 정의한 HierarchyNode 타입의 객체가 리턴되며, 각각의 프로퍼티에 대한 설명은 다음과 같습니다.

  • children : 자식 노드들
  • data : 사용자가 정의한 데이터
  • depth : 트리에서 자신의 노드의 깊이
  • height : 자식 노드의 최대 깊이
  • parent : 부모 노드 없으면 null
const root = hierarchy<TreeData>(TREE_DATA);

console.log(root);
{
children: [Node, Node, Node, Node],
data: {id: "Chaos", children: Array(4)}
depth: 0,
height: 2,
parent: null
}

레이아웃 객체 생성하기

앞에서 생성한 객체를 가지고, D3에서 제공하는 레이아웃 객체를 생성할 수 있습니다. 아래는 트리를 그리기 위한 레이아웃 객체를 생성하는 코드이며, HierarchyNode 타입을 상속한 HierarchyPointNode 타입의 객체로 변경됩니다.

x, y 프로퍼티가 추가된 것을 확인할 수 있으며, 캔버스나 SVG로 무엇인가 그릴 때, 해당 값을 그대로 사용하면 됩니다.

HierarchyNode 타입을 상속하는 타입은 HierarchyPointNode 외에도 HierarchyRectangularNode, HierarchyCircularNode 타입이 있습니다.

const treeLayout = tree().size([WIDTH, HEIGHT]);
treeLayout(root);

console.log(root);
{
children: [Node, Node, Node, Node],
data: {id: "Chaos", children: Array(4)}
depth: 0,
height: 2,
parent: null,
x: 233.33333333333334,
y: 0
}

로우셋을 계층 데이터로 변환하기

때로는 children 프로퍼티가 포함되어있지 않고, 부모 키만 알고 있는 데이터를 가지고 있을 수 있습니다.

interface RowData1 {
id: string;
parentId?: string;
}
interface RowData2 {
id2: string;
pid?: string;
}

const ROW_DATA_1: RowData1[] = [
{ id: 'Chaos' },
{ id: 'Gaia', parentId: 'Chaos' },
{ id: 'Eros', parentId: 'Chaos' },
{ id: 'Erebus', parentId: 'Chaos' },
{ id: 'Tartarus', parentId: 'Chaos' },
{ id: 'Mountains', parentId: 'Gaia' },
{ id: 'Pontus', parentId: 'Gaia' },
{ id: 'Uranus', parentId: 'Gaia' },
];

const ROW_DATA_2: RowData2[] = [
{ id2: 'Chaos' },
{ id2: 'Gaia', pid: 'Chaos' },
{ id2: 'Eros', pid: 'Chaos' },
{ id2: 'Erebus', pid: 'Chaos' },
{ id2: 'Tartarus', pid: 'Chaos' },
{ id2: 'Mountains', pid: 'Gaia' },
{ id2: 'Pontus', pid: 'Gaia' },
{ id2: 'Uranus', pid: 'Gaia' },
];

D3에서는 children과 마찬가지로 id와 parentId 프로퍼티를 스스로 인식합니다. stratify 함수를 사용하면 hierarchy 함수와 동일한 객체를 리턴하게 됩니다.

하지만 데이터 id와 parentId 프로퍼티가 포함되어 있지 않다면 id와 parentId 메소드를 통해 부모-자식 관계를 설정할 수 있습니다.

const root1 = stratify<RowData1>()(ROW_DATA_1);
const root2 = stratify<RowData2>()
.id((data) => data.id2)
.parentId((data) => data.pid)(ROW_DATA_2);

console.log(root2);
{
children: [Node, Node, Node, Node],
data: {id: "Chaos", children: Array(4)}
depth: 0,
height: 2,
parent: null
}

Hierarchy 객체의 메소드 소개

계층 데이터를 쉽게 핸들링할 수 있는 몇가지 메소드들을 소개합니다.

const chaos = root2;
const gaia = chaos.children[0];
const pontus = chaos.children[0].children[1]
const tartarus = chaos.children[3];

ancestors

자신을 포함하여 루트까지 모든 부모 노드의 배열을 반환합니다.

gaia.ancestors();

ancestors-1

pontus.ancestors();

ancestors-2

descendants

자신을 포함하여 모든 자식 노드의 배열을 반환합니다.

gaia.descendants();

descendants

leaves

해당 노드의 자식 중에 자식이 없는 노드의 배열을 반환합니다

gaia.leaves();

leaves

path

해당 노드부터 대상 노드까지 연결된 모든 노드의 배열을 반환합니다.

노드 순서

Tartarus -> Chaos -> Gaia -> Pontus

tartarus.path(pontus);

path

해당 노드의 자식 링크를 나타내는 객체 배열을 반환합니다. 각 링크 객체의 target은 자식이고, source는 부모입니다. gaia의 자식 노드인 mountains, pontus, uranus를 target으로 가진 HierarchyPointLink 타입을 가지는 배열을 리턴합니다.

앞에서 트리 레이아웃을 사용했기 때문에 HierarchyLink가 아닌 HierarchyPointLink 타입의 객체를 리턴합니다. 그 밖에도 HierarchyCircularLink, HierarchyRectangularLink 타입이 있습니다.

gaia.links();

descendants