Skip to content

Latest commit

Β 

History

History
171 lines (109 loc) Β· 6.1 KB

File metadata and controls

171 lines (109 loc) Β· 6.1 KB

Duct 0.11 섀계 μ˜μ‚¬ κ²°μ •

머리말

Duct 0.11 ν”„λ‘œμ νŠΈμ˜ μ£Όμš” λ³€κ²½ 사항을 μ†Œκ°œν•©λ‹ˆλ‹€. 이 λ¬Έμ„œλŠ” λ³€κ²½ 사항을 μžμ„Ένžˆ μ„€λͺ…ν•˜κ³  κ·Έλ ‡κ²Œ κ΅¬ν˜„ 된 이유λ₯Ό μ„€λͺ…ν•©λ‹ˆλ‹€.

이 λ³€κ²½ 사항은 μ•ŒνŒŒ 버전에 κ΅¬ν˜„λ˜μ–΄ 있고 μ•„λž˜μ™€ 같이 ν…ŒμŠ€νŠΈ ν•΄λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€:

lein new duct-alpha <project> <hints...>

λͺ¨λ“ˆ

0.10 λ²„μ „μ—μ„œ

0.10 μ΄ν•˜ λ²„μ „μ—μ„œλŠ” λͺ¨λ“ˆμ„ λ§Œλ“€ λ•Œ μ•„λž˜ 처럼 μ½”λ“œλ₯Ό μž‘μ„±ν–ˆμŠ΅λ‹€:

(defmulti ig/init-key ::module [_ options]
  {:req [::precondition]
   :fn  (fn [config] config)})

λͺ¨λ“ˆμ„ μ΄ˆκΈ°ν™” ν•˜λŠ” ν‚€λŠ” 맡을 λ¦¬ν„΄ν•©λ‹ˆλ‹€. :fn ν‚€λŠ” 섀정을 λ³€κ²½ν•˜λŠ”λ° μ‚¬μš©ν•˜λŠ” 순수 ν•¨μˆ˜μž…λ‹ˆλ‹€. :req ν‚€λŠ” λͺ¨λ“ˆμ΄ μ΄ˆκΈ°ν™” 되기 전에 섀정에 ν•„μš”ν•œ ν•„μˆ˜ ν‚€ μ»¬λ ‰μ…˜μž…λ‹ˆλ‹€. ν•„μˆ˜ ν‚€λŠ” Ductκ°€ 각 λͺ¨λ“ˆμ΄ μ˜μ‘΄μ„±μ— 맞좰 μˆœμ„œλŒ€λ‘œ μ μš©ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•©λ‹ˆλ‹€.

λ¬Έμ œλŠ” 이미 Integrant에 μ˜μ‘΄μ„±μ„ κ΄€λ¦¬ν•˜κΈ° μœ„ν•œ 잘 λ§Œλ“€μ–΄μ§„ κΈ°λŠ₯이 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μ˜μ‘΄μ„± μˆœμ„œλ₯Ό μœ„ν•œ 두 개의 κ°œλ³„ μ‹œμŠ€ν…œμ΄ μžˆλŠ” 것 보닀 λͺ¨λ“ˆ 킀와 일반 ν‚€λ₯Ό ν•˜λ‚˜μ˜ μ‹œμŠ€ν…œμœΌλ‘œ μ“°λŠ” 것이 더 ν•©λ¦¬μ μž…λ‹ˆλ‹€.

0.11 λ²„μ „μ—μ„œ

이전 λ²„μ „μ˜ Integrant은 섀정을 λ³€κ²½ν•˜λŠ” 방법 외에 μ°Έμ‘° ν‚€λ₯Ό μΆ”κ°€ν•  방법이 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“ˆμ΄ λ‹€λ₯Έ 킀에 의쑴 ν•œλ‹€λ©΄ μžλ™μœΌλ‘œ μ°Έμ‘°λ₯Ό μΆ”κ°€ν•  수 μžˆλŠ” 방법이 ν•„μš”ν•©λ‹ˆλ‹€.

이λ₯Ό μœ„ν•΄ Integrant 0.7에 prep-key λ©€ν‹°λ©”μ„œλ“œκ°€ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. prep-key λ©€ν‹°λ©”μ„œλ“œλŠ” 섀정이 μ΄ˆκΈ°ν™”λ˜κΈ° 전에 prep ν•¨μˆ˜μ— μ˜ν•΄ λΆˆλ¦½λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 섀정을 μž‘μ„±ν•œ 후에도 μ°Έμ‘°λ₯Ό μΆ”κ°€ν•΄ μ˜μ‘΄μ„± μˆœμ„œλ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

Duct 버전 0.11 이후 λͺ¨λ“ˆμ€ λ‹€μŒκ³Ό 같이 μž‘μ„±ν•©λ‹ˆλ‹€:

(defmulti ig/prep-key ::module [_ options]
  (assoc options ::requires (ig/ref ::precondition)))

(defmulti ig/init-key ::module [_ options]
  (fn [config] config))

prep 단계에 λͺ¨λ“ˆμ΄ ν•„μš”ν•œ λ‹€λ₯Έ 킀에 λŒ€ν•œ μ°Έμ‘°λŠ” ::requires 프라이빗 킀에 μΆ”κ°€ λ©λ‹ˆλ‹€. λͺ¨λ“ˆμ΄ μ΄ˆκΈ°ν™” λ λ•Œ ::precondition ν‚€ λ‹€μŒμ— ::module ν‚€κ°€ μ΄ˆκΈ°ν™” λ˜λ„λ‘ 보μž₯ν•΄ μ€λ‹ˆλ‹€.

ν”„λ‘œν•„

0.10 λ²„μ „μ—μ„œ

이전 λ²„μ „μ˜ ductμ—λŠ” λͺ¨λ“ˆ 킀와 일반 Integrant ν‚€κ°€ 같은 섀정에 μžˆμ—ˆμŠ΅λ‹ˆλ‹€:

{:duct.core/project-ns foo
 :duct.module/example  {}}

ν•˜μ§€λ§Œ 이런 방식을 μ“°λ©΄ μ΄ˆκΈ°ν™”λ₯Ό ν•˜κΈ° 전에 λͺ¨λ“ˆ 킀와 일반 ν‚€κ°€ λΆ„λ¦¬λ˜μ–΄μ•Ό ν•˜λŠ” λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. 또 λͺ¨λ“ˆ 킀와 일반 ν‚€κ°€ 레퍼런슀λ₯Ό κ³΅μœ ν•˜λ©΄ λ¬Έμ œκ°€ 될 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

같은 μ„€μ • 맡에 λͺ¨λ“ˆ 킀와 일반 ν‚€κ°€ ν•¨κ»˜ μžˆλŠ” 것은 νŽΈλ¦¬ν•˜μ§€λ§Œ 좔상화λ₯Ό κΉ° 수 μžˆμŠ΅λ‹ˆλ‹€.

0.11 λ²„μ „μ—μ„œ

ν•΄κ²° 방법은 λͺ¨λ“ˆ ν‚€λ₯Ό 일반 ν‚€λ‘œ λΆ€ν„° λͺ…ν™•ν•˜κ²Œ λΆ„λ¦¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. Duct 0.11 λ²„μ „μ—λŠ” λͺ¨λ“  λͺ¨λ“ˆ 킀에 이 방법을 μ μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 일반 ν‚€λŠ” μ•„λž˜μ™€ 같이 ν”„λ‘œν•„ μ•ˆμ— μ”λ‹ˆλ‹€:

{:duct.profile/base   {:duct.core/project-ns foo}
 :duct.module/example {}}

ν”„λ‘œν•„μ€ λ‹¨μˆœνžˆ ν”„λ‘œν•„ μ„€μ • 값을 전체 μ„€μ • 값에 meta-merge ν•˜λŠ” λͺ¨λ“ˆ μž…λ‹ˆλ‹€.

κ·Έ κ²°κ³Ό 계측 사이에 λͺ…ν™•νžˆ λΆ„λ¦¬λœ 계측 ꡬ쑰λ₯Ό λ§Œλ“­λ‹ˆλ‹€: Duct 섀정은 λ™μž‘ν•˜λŠ” μ‹œμŠ€ν…œμ— ν•„μš”ν•œ μ˜μ‘΄μ„±κ³Ό ν•¨κ»˜ Integrant 섀정을 λ§Œλ“­λ‹ˆλ‹€.

ν”„λ‘œν•„μ΄ λ‹€λ₯Έ λͺ¨λ“ˆμ΄ μ‹œμž‘λ˜κΈ° 전에 μ‹€ν–‰ λ˜λŠ” 것을 보μž₯ν•˜λ €λ©΄ μ˜μ‘΄μ„±μ„ μ •μ˜ν•  방법이 ν•„μš”ν•©λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ Integrant 0.7 버전에 refsets κΈ°λŠ₯이 μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Refset은 ref 처럼 λ™μž‘ν•˜λŠ”λ° λ§€μΉ­λ˜λŠ” λͺ¨λ“  ν‚€μ˜ set을 생성해 μ€€λ‹€λŠ” 점이 ref와 λ‹€λ¦…λ‹ˆλ‹€.

:duct/profile 을 μƒμ†ν•œ ν‚€κ°€ μ‹€ν–‰ 된 후에 :duct/module 을 μƒμ†ν•œ ν‚€λ₯Ό μ μš©ν•˜κΈ° μœ„ν•΄ refset을 μ“Έ 수 μžˆμŠ΅λ‹ˆλ‹€. duct.core 에 μ•„λž˜μ™€ 같이 μ •μ˜ λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€:

(defmethod ig/prep-key :duct/module [_ profile]
  (assoc profile ::requires (ig/refset :duct/profile)))

ref와 refset, ν‚€μ›Œλ“œ 상속 간에 λ³΅μž‘ν•˜μ§€λ§Œ 예츑 κ°€λŠ₯ν•œ μ˜μ‘΄μ„± κ·Έλž˜ν”„λ₯Ό μ„€μ • ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Includes

In 0.10

In version 0.10 and below, includes were handled by a special key, :duct.core/include:

{:duct.core/include ["example"]}

This will look for a resource named example.edn and meta-merge it into the configuration.

There are two problems with this approach.

The first and most obvious issue is that it requires one key to have a special function, one that isn't defined by a standard multimethod. It cannot be a module because it's side-effectful.

The second issue is that it introduces new side-effects after the configuration has been read. Ideally we want reading the configuration to happen at the same step.

In 0.11

In version 0.11 the :duct.core/include key is replaced with the #duct/include reader tag. The tag is replaced by the contents of the referenced resource. If we want to merge it into the configuration, we place it in a profile:

{:duct.profile/example #duct/include "example"]}

This ensures all the included configurations are read together by read-config, and moves the complexities of merging into the profiles.

This approach also allows smaller chunks of data to be included from external files, rather than full configurations.

Summary

The changes represent an overall simplification of the module and include system:

  • Modules and normal components are separated.
  • Modules no longer use their own dependency management.
  • Merging is separated out into profiles.
  • Including other configurations happens at read time.
  • No keys with 'special' functionality.

In addition to the simplification, extra functionality has been added:

  • prep-key removes the need for modules in simple cases
  • refset allows for more sophisticated dependencies