Hypermedia-Driven Applications

Carson Gross

#기원

λ…Όμ œ: MPA - 닀쀑 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜

λ°˜λ…Όμ œ: SPA - 단일 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜

μ’…ν•©: HDA - ν•˜μ΄νΌλ―Έλ””μ–΄ ꡬ동 μ• ν”Œλ¦¬μΌ€μ΄μ…˜

--@htmx_org

#ν•˜μ΄νΌλ―Έλ””μ–΄ ꡬ동 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ•„ν‚€ν…μ²˜

ν•˜μ΄νΌλ―Έλ””μ–΄ ꡬ동 μ• ν”Œλ¦¬μΌ€μ΄μ…˜(Hypermedia Driven Application, HDA) μ•„ν‚€ν…μ²˜λŠ” 전톡적인 닀쀑 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜(MPA)의 λ‹¨μˆœμ„±κ³Ό μœ μ—°μ„±μ„ 단일 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜(SPA)의 ν–₯μƒλœ μ‚¬μš©μž κ²½ν—˜κ³Ό κ²°ν•©ν•œ μƒˆλ‘œμš΄/였래된 μ ‘κ·Ό λ°©μ‹μž…λ‹ˆλ‹€.

HDA μ•„ν‚€ν…μ²˜λŠ” μ›Ήμ˜ κΈ°μ‘΄ HTML 인프라λ₯Ό ν™•μž₯ν•˜μ—¬ ν•˜μ΄νΌλ―Έλ””μ–΄ κ°œλ°œμžκ°€ 더 κ°•λ ₯ν•œ ν•˜μ΄νΌλ―Έλ””μ–΄ ꡬ동 μƒν˜Έμž‘μš©μ„ 생성할 수 μžˆλ„λ‘ ν•¨μœΌλ‘œμ¨ μ΄λŸ¬ν•œ λͺ©ν‘œλ₯Ό λ‹¬μ„±ν•©λ‹ˆλ‹€.

REST μ•„ν‚€ν…μ²˜μ˜ μ œμ•½ κ°œλ…μ„ λ”°λ₯΄λ©°, λ‹€μŒκ³Ό 같은 두 가지 μ œμ•½μ΄ HDA μ•„ν‚€ν…μ²˜λ₯Ό νŠΉμ§•μ§“μŠ΅λ‹ˆλ‹€:

이 두 가지 μ œμ•½μ„ μ±„νƒν•¨μœΌλ‘œμ¨, HDA μ•„ν‚€ν…μ²˜λŠ” SPA μ•„ν‚€ν…μ²˜κ°€ 그렇지 μ•Šμ€ λ°©μ‹μœΌλ‘œ μ›Ήμ˜ μ›λž˜ REST-ful μ•„ν‚€ν…μ²˜ 내에 λ¨Έλ¬΄λ¦…λ‹ˆλ‹€.

특히, HDAλŠ” ν•˜μ΄νΌλ―Έλ””μ–΄κ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒνƒœμ˜ μ—”μ§„μœΌλ‘œ μž‘λ™ν•˜λŠ” 것(HATEOAS)을 계속 μ‚¬μš©ν•˜μ§€λ§Œ, λŒ€λΆ€λΆ„μ˜ SPAλŠ” ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ λͺ¨λΈκ³Ό 데이터(API)λ₯Ό μ‚¬μš©ν•˜κ³  HATEOASλ₯Ό ν¬κΈ°ν•©λ‹ˆλ‹€.

#HDA ν”„λž˜κ·Έλ¨ΌνŠΈ μ˜ˆμ‹œ

htmx의 μ‹€μ‹œκ°„ 검색 μ˜ˆμ‹œλ₯Ό κ³ λ €ν•΄λ³΄μ„Έμš”:

<h3> 
  Search Contacts 
  <span class="htmx-indicator"> 
    <img src="/img/bars.svg"/> Searching... 
   </span> 
</h3>
<input class="form-control" type="search" 
       name="search" placeholder="Begin Typing To Search Users..." 
       hx-post="/search" 
       hx-trigger="keyup changed delay:500ms, search" 
       hx-target="#search-results" 
       hx-indicator=".htmx-indicator">

<table class="table">
    <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Email</th>
    </tr>
    </thead>
    <tbody id="search-results">
    </tbody>
</table>

이 UX νŒ¨ν„΄μ€ 일반적으둜 SPA와 μ—°κ΄€λ˜μ§€λ§Œ, 이 κ²½μš°λŠ” HTML λ‚΄μ—μ„œ μ™„μ „νžˆ λ‹¬μ„±λ˜λ©°, HTMLκ³Ό μ‘°ν™”λ₯Ό μ΄λ£Ήλ‹ˆλ‹€.

이 μ˜ˆμ‹œλŠ” HDA의 본질적인 νŠΉμ§•μ„ 효과적으둜 λ³΄μ—¬μ€λ‹ˆλ‹€:

#HDAμ—μ„œμ˜ μŠ€ν¬λ¦½νŒ…

Code-On-DemandλŠ” μ›Ήμ˜ μ›λž˜ REST-ful μ•„ν‚€ν…μ²˜μ˜ 선택적 μ œμ•½ μ‘°κ±΄μž…λ‹ˆλ‹€.

λ§ˆμ°¬κ°€μ§€λ‘œ, HDA μ•„ν‚€ν…μ²˜λŠ” λ§ˆμ§€λ§‰ 선택적 μ œμ•½ 쑰건을 κ°€μ§‘λ‹ˆλ‹€:

이것은 Roy Fielding이 μžμ‹ μ˜ λ…Όλ¬Έμ—μ„œ μ–ΈκΈ‰ν•œ Code-On-Demand에 λŒ€ν•œ 우렀λ₯Ό λ‹€λ£Ήλ‹ˆλ‹€:

κ·ΈλŸ¬λ‚˜, (Code-On-DemandλŠ”) κ°€μ‹œμ„±μ„ μ€„μ΄λ―€λ‘œ, REST λ‚΄μ—μ„œ 선택적 μ œμ•½μΌ λΏμž…λ‹ˆλ‹€.

μŠ€ν¬λ¦½νŒ…μ„ HTML 내에 직접 λ‚΄μž₯ν•¨μœΌλ‘œμ¨ κ°€μ‹œμ„±μ΄ ν–₯μƒλ˜λ©°, ν–‰λ™μ˜ 지역성 μ†Œν”„νŠΈμ›¨μ–΄ 섀계 원칙을 μΆ©μ‘±μ‹œν‚΅λ‹ˆλ‹€.

이 μ„Έ 가지 μ ‘κ·Ό 방식은 이 μ„Έ 번째 μ œμ•½μ„ λ§Œμ‘±μ‹œν‚€λŠ” μŠ€ν¬λ¦½νŒ… λ°©λ²•λ“€μž…λ‹ˆλ‹€: hyperscript, AlpineJS 및 VanillaJS (HTML μš”μ†Œμ— 직접 λ‚΄μž₯된 경우).

λ‹€μŒμ€ 각 μ ‘κ·Ό λ°©μ‹μ˜ μ˜ˆμ‹œμž…λ‹ˆλ‹€:

<!-- hyperscript -->
<button _="on click toggle .red-border">
  Toggle Class
</button>

<!-- Alpine JS -->
<button @click="open = !open" :class="{'red-border' : open, '' : !open}">
  Toggle Class
</button>

<!-- VanillaJS -->
<button onclick="this.classList.toggle('red-border')">
  Toggle Class
</button>

HDAμ—μ„œλŠ” ν•˜μ΄νΌλ―Έλ””μ–΄(HTML)κ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ΅¬μΆ•ν•˜λŠ” 데 μžˆμ–΄ μ£Όμš” λ§€μ²΄μ΄λ―€λ‘œ:

μŠ€ν¬λ¦½νŒ…μ€ 기쑴의 ν•˜μ΄νΌλ―Έλ””μ–΄(HTML)λ₯Ό λ³΄κ°•ν•˜μ§€λ§Œ, 이λ₯Ό λŒ€μ²΄ν•˜κ±°λ‚˜ HDA의 κΈ°λ³Έ REST-ful μ•„ν‚€ν…μ²˜λ₯Ό ν›Όμ†ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

#HDA μŠ€νƒ€μΌ 라이브러리

λ‹€μŒ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” κ°œλ°œμžκ°€ HDAλ₯Ό λ§Œλ“€ 수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€:

λ‹€μŒ μŠ€ν¬λ¦½νŒ… λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 적절히 μ‚¬μš©λ  λ•Œ HDA μ ‘κ·Ό 방식을 λ³΄μ™„ν•©λ‹ˆλ‹€:

#κ²°λ‘ 

HDA μ•„ν‚€ν…μ²˜λŠ” 두 가지 이전 μ•„ν‚€ν…μ²˜, 즉 μ›λž˜μ˜ 닀쀑 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜(MPA) μ•„ν‚€ν…μ²˜μ™€ (μƒλŒ€μ μœΌλ‘œ) μƒˆλ‘œμš΄ 단일 νŽ˜μ΄μ§€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ•„ν‚€ν…μ²˜μ˜ μ’…ν•©μž…λ‹ˆλ‹€.

이 μ•„ν‚€ν…μ²˜λŠ” 두 μ•„ν‚€ν…μ²˜μ˜ μž₯점을 κ²°ν•©ν•˜λ €κ³  μ‹œλ„ν•©λ‹ˆλ‹€: REST-ful μ•„ν‚€ν…μ²˜λ₯Ό μ‚¬μš©ν•˜λŠ” MPA의 λ‹¨μˆœμ„±κ³Ό μ‹ λ’°μ„±, 그리고 λ§Žμ€ 경우 SPA와 λ™λ“±ν•œ μ‚¬μš©μž κ²½ν—˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€.

</>