애플리케이션 사용 사례 정의
μ΄ μΉμ μμλ Lino CLIλ₯Ό μ¬μ©νμ¬ μ ν리μΌμ΄μ μ μ¬μ© μ¬λ‘λ₯Ό μ μνλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€. μ¬μ© μ¬λ‘λ μ¬μ©μ λλ μΈλΆ μμ€ν κ³Ό μ ν리μΌμ΄μ κ°μ ꡬ체μ μΈ μνΈ μμ©μ λνλ΄λ©°, λΉμ¦λμ€ κ·μΉμ μΊ‘μννκ³ λλ©μΈ μ€μ¬ μν€ν μ²λ₯Ό μ΄μ§ν©λλ€. μ°λ¦¬λ CQRS ν¨ν΄μ ν΅ν΄ μ½κΈ° λ° μ°κΈ° μμ μ λΆλ¦¬λ₯Ό λ€λ£¨κ³ , Result Patternμ μ¬μ©νμ¬ μλ΅ λ°νμ νμ€ννλ λ°©λ²μ μ€λͺ ν©λλ€.
CQRS (Command Query Responsibility Segregation) ν¨ν΄μ μ ν리μΌμ΄μ μ μνλ₯Ό λ³κ²½νλ μμ (Commands)κ³Ό λ¨μν λ°μ΄ν°λ₯Ό μ‘°ννλ μμ (Queries)μ λΆλ¦¬νλ κ²μ μ μν©λλ€. μ΄ μ κ·Ό λ°©μμ κ° μμ μ νμ λ 립μ μΌλ‘ μ΅μ νν μ μκ² νμ¬ νμ₯μ±, μ±λ₯, μμ€ν μ μ§ κ΄λ¦¬λ₯Ό ν₯μμν΅λλ€.
Result Patternμ μμ μ λ°ν κ°μ νμ€ννκΈ° μν΄ μ¬μ©λλ©°, μ±κ³΅ λλ μ€ν¨ μ¬λΆ, μ€λ₯ λ©μμ§, κ²°κ³Ό λ°μ΄ν°λ₯Ό μΊ‘μνν©λλ€. μ΄λ₯Ό ν΅ν΄ μ ν리μΌμ΄μ μ λ€μν κ³μΈ΅μμ μΌκ΄λ μλ΅ μ²λ¦¬κ° κ°λ₯ν΄μ§λλ€.
μ°λ¦¬λ Commands λ° Queries νμΌμ΄ μ΄λ»κ² ꡬμ±λλμ§, λ°μ΄ν° μ ν¨μ± κ²μ¬κ° μ΄λ»κ² μ΄λ£¨μ΄μ§λμ§, Handlersμ λλ©μΈ λ‘μ§μ΄ μ΄λ»κ² μ μ©λλμ§, κ·Έλ¦¬κ³ κ²°κ³Όλ₯Ό νμ€νλ λ°©μμΌλ‘ λ°ννλ λ°©λ²μ μ΄ν΄λ³Ό κ²μ λλ€. μ΄ λͺ¨λ κ³Όμ μ Lino CLIλ₯Ό ν΅ν΄ ν΄λΉ κ΅¬μ± μμλ€μ μλμΌλ‘ μμ±ν¨μΌλ‘μ¨ μ΄λ£¨μ΄μ§λλ€.
μ°Έκ³ : νμλ μλμ§λ§, νμ¬ Linoλ μ ν리μΌμ΄μ
κ³μΈ΅μμ CQRS ν¨ν΄μ μ μ©νκΈ° μν λ κ°μ§ μ΅μ
μ μ 곡ν©λλ€: Jimmy Bogardμ MediatR
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ Mediator ν¨ν΄, λλ Martin Othamarμ Mediator
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ λ°©μμ
λλ€.
μ¬μ© μ¬λ‘ κ°μ
μ¬μ© μ¬λ‘λ μ¬μ©μ λλ μΈλΆ μμ€ν κ³Ό μ ν리μΌμ΄μ κ°μ μμ ν μνΈμμ©μ λνλ΄λ©°, νΉμ λΉμ¦λμ€ μλ리μ€λ₯Ό μ€λͺ ν©λλ€. Linoμμλ κ° μ¬μ© μ¬λ‘κ° λ€μκ³Ό κ°μ΄ λλ©λλ€:
- λͺ λ Ή(Command): μμ€ν μνλ₯Ό λ³κ²½νλ €λ μλ(μμ±, μ λ°μ΄νΈ, μμ λ±)λ₯Ό λνλ λλ€.
- 쿼리(Query): λλ©μΈ μνλ₯Ό λ³κ²½νμ§ μκ³ λ°μ΄ν°λ₯Ό μ‘°ννλ €λ μλλ₯Ό λνλ λλ€.
μ΄λ¬ν λΆλ¦¬λ μ½λμ λͺ νμ±μ λμ΄κ³ , ν μ€νΈλ₯Ό μ©μ΄νκ² νλ©°, μ½κΈ° λ° μ°κΈ° μμ μ λ 립μ μΈ νμ₯μ±μ κ°λ₯νκ² νκ³ , ν΄λ¦° μν€ν μ² μμΉκ³Ό λλ©μΈ μ£Όλ μ€κ³ (DDD)μ λͺ¨λ² μ¬λ‘μ λΆν©ν©λλ€.
λͺ λ Ή(Commands)
λͺ
λ Ή(Command)μ μμ€ν
μνλ₯Ό λ³κ²½νλ μμ
μ μννλ λ° νμν λ°μ΄ν°λ§ λ΄κ³ μλ λΆλ³ λ©μμ§μ
λλ€(μ: CreateInvoice
, DeactivateUser
).
λͺ
λ Ήμ μμ
μνμ νμμ μΈ μ λ³΄λ§ ν¬ν¨ν΄μΌ ν©λλ€.
λͺ λ Ήμ νΉμ§
- λΆλ³μ±:
record
λλ κ³΅κ° setμκ° μλget
λ§ μλ ν΄λμ€ ννλ‘ κ΅¬νλ©λλ€. - λͺ
λ Ήν μ΄λ¦: μ€νλ μμ
μ λ°μνλ©° μλ₯Ό λ€μ΄
CreateOrder
,UpdateCustomerAddress
λ±μ΄ μμ΅λλ€. - μ΅μνμ λ°μ΄ν°: μμ μ€νμ νμν νλλ§ ν¬ν¨νλ©° λλμ λ°μ΄ν°λ₯Ό λ°ννμ§ μμ΅λλ€.
- λ 립μ μΈ κ²μ¦: κ° λͺ λ Ήμ μ체 κ²μ¦ κ·μΉμ κ°μ§λ©°, νΈλ€λ¬(Handler)μ μ λ¬λκΈ° μ μ μΌκ΄μ±μ 보μ₯ν©λλ€.
λͺ λ Ή κ²μ¦κΈ°(Command Validators)
λͺ λ Ή κ²μ¦κΈ°λ λͺ λ Ήμ΄ μ¬λ°λ₯΄κ² νμ±λμλμ§ λ° λΉμ¦λμ€ μꡬ μ¬νμ μΆ©μ‘±νλμ§ νΈλ€λ¬μ μ λ¬νκΈ° μ μ νμΈν©λλ€. Linoμμλ .NET νλ‘μ νΈμμ λ리 μ¬μ©λκ³ κ·μΉ μμ±μ Fluent APIλ₯Ό μ 곡νλ FluentValidation λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν©λλ€.
μΌλ° κ²μ¦ κ·μΉ
NotEmpty
,NotNull
- νμ νλμ©InclusiveBetween
- μ«μ λ²μμ©(μ: κΈμ‘, μ΅μ/μ΅λ μλ)MaximumLength
,MinimumLength
- λ¬Έμμ΄ κΈΈμ΄μ©RuleForEach
- 컬λ μ (List<T>
) νλͺ© κ²μ¦μ©Must
- μ¬μ©μ μ μ κ·μΉμ©(μ: λ¬Έμ νμ, λ μ§ κ²μ¦)
λͺ λ Ή νΈλ€λ¬(Command Handlers)
λͺ
λ Ή νΈλ€λ¬λ ν΄λΉ λͺ
λ Ήκ³Ό κ΄λ ¨λ λλ©μΈ λ‘μ§μ μ€ννλ μ±
μμ΄ μμ΅λλ€. 리ν¬μ§ν 리, μμ
λ¨μ(IUnitOfWork
), 보쑰 μλΉμ€λ€μ μ‘°μ¨νκ³ νμ μ λλ©μΈ μ΄λ²€νΈλ₯Ό λ°μμν΅λλ€.
νΈλ€λ¬ ꡬν ν¨ν΄
- μμ‘΄μ± μ£Όμ μ ν΅ν΄ 리ν¬μ§ν 리, μΈλΆ μλΉμ€, UnitOfWork λ±μ μμ‘΄μ±μ λ°μ΅λλ€.
- λλ©μΈ μν°ν°λ₯Ό λ§€ννκ³ μΈμ€ν΄μ€ννμ¬ μ΄κΈ° μΌκ΄μ±μ 보μ₯ν©λλ€.
- λΉμ¦λμ€ κ·μΉ μ μ©(μΆκ° κ²μ¦, κ° κ³μ°, λλ©μΈ μ΄λ²€νΈ νΈλ¦¬κ±°)
IUnitOfWork
λλ μ§μ 리ν¬μ§ν 리λ₯Ό ν΅ν΄ λ³κ²½μ¬νμ μμνν©λλ€.- μ±κ³΅ λλ μ€ν¨λ₯Ό λνλ΄λ λͺ
λ Ή κ²°κ³Ό(Command Result)(
Result<T>
)λ₯Ό λ°νν©λλ€.
λͺ λ Ή κ²°κ³Όμ Result ν¨ν΄
λͺ
λ Ή κ²°κ³Όλ νΈμΆμ(μ: API λλ νλ°νΈμλ)κ° κ³μ μ§ννλ λ° νμν μ΅μνμ λ°μ΄ν°λ§ ν¬ν¨νλ κ°λ¨ν DTOμ¬μΌ ν©λλ€. μΌλ°μ μΌλ‘ μμ±λκ±°λ μ
λ°μ΄νΈλ μν°ν°μ μλ³μ(Id
)μ μ€ν¨ μ μ€λ₯μ λν νμ€νλ μ 보λ₯Ό ν¬ν¨ν©λλ€.
λͺ
λ Ήμ΄ μ€ν¨ν μ μλ μλ리μ€μμλ Result ν¨ν΄μ μ¬μ©ν©λλ€. μ΄ ν¨ν΄μ μ±κ³΅ λλ μ€ν¨μΌ μ μλ μμ
κ²°κ³Όλ₯Ό μΊ‘μννλ μΆμνμ
λλ€. .NETμμλ Result<T>
μ κ°μ νμ
(λλ μ μ¬ λΌμ΄λΈλ¬λ¦¬)μ μ£Όλ‘ μ¬μ©νλ©°:
- μ±κ³΅ μ
Value
λ₯Ό μ€μ ν μ μμ΅λλ€(μ: λ¨μ DTO). - μ€ν¨ μ νμ€νλ μ½λ λλ λ©μμ§(
Error
)λ₯Ό μ μ₯νλ©°, HTTP μ½λ, κ²μ¦ μΈλΆμ¬ν λ± μΆκ° λ©νλ°μ΄ν°κ° ν¬ν¨λ μ μμ΅λλ€. - API μ 체μμ μ€λ₯ μ²λ¦¬ νλ¦μ ν΅ν©νμ¬ κ³μΈ΅ κ° μΌκ΄μ±μ μ μ§ν©λλ€.
CLIλ₯Ό μ¬μ©ν λͺ λ Ή μμ±
Linoλ λ€μ λͺ λ Ήμ΄λ₯Ό ν΅ν΄ μ λͺ λ Ήμ νμν λͺ¨λ μν°ν©νΈλ₯Ό μ½κ² μμ±ν μ μμ΅λλ€:
lino command new
μ΄ λͺ λ Ήμ μ€ννλ©΄ λνν λ§λ²μ¬κ° λ€μμ μμ²ν©λλ€:
- μλΉμ€ β λͺ λ Ήμ΄ μμ±λ μλΉμ€ μ΄λ¦
- λͺ¨λ β λͺ¨λνλ μλΉμ€μ κ²½μ° λμ λͺ¨λ μ μ
- μν°ν° β λͺ λ Ήκ³Ό κ΄λ ¨λ λλ©μΈ μν°ν°(μ ν μ¬νμ΄μ§λ§ κΆμ₯)
- λͺ
λ Ή μ΄λ¦ β μ΅μ’
λͺ
λ Ή μ΄λ¦(μ:
CreateOrder
)
νμΈ ν Linoκ° μλμΌλ‘ λ€μ νμΌλ€μ μμ±ν©λλ€:
CreateOrderCommand.cs
CreateOrderCommandValidator.cs
CreateOrderCommandHandler.cs
CreateOrderCommandResult.cs
μμ±λ ꡬ쑰 μμ
CreatePerson
λͺ
λ Ήμ μλ‘ λ€μ΄ λ³΄κ² μ΅λλ€. μμ±λ ꡬ쑰λ λ€μκ³Ό μ μ¬ν©λλ€:
MyApp/ βββ src/ βββ Services/ βββ MyService/ βββ Application/ βββ MyApp.MyService.Application.csproj βββ UseCases/ βββ People/ βββ Commands/ β βββ CreatePerson/ β βββ CreatePersonCommand.cs β βββ CreatePersonCommandValidator.cs β βββ CreatePersonCommandHandler.cs β βββ CreatePersonCommandResult.cs βββ Queries/ βββ ...
쿼리(Queries)
쿼리λ λλ©μΈμ μνλ₯Ό λ³κ²½νμ§ μκ³ λ°μ΄ν°λ₯Ό μ‘°ννλ €λ μλλ₯Ό λνλ λλ€. 쿼리λ μ½κΈ° ν¨μ¨μ±μ μν΄ μ€κ³λμμΌλ©°, μμ²λμ§ μμ κ²½μ° μ 체 μν°ν°λ₯Ό λ‘λνμ§ μκ³ νμν νλλ§ μ νν λ°νν©λλ€.
쿼리μ νΉμ§
- λΆλ³μ± β 컀맨λμ λ§μ°¬κ°μ§λ‘, 쿼리λ μμ±λ ν λ³κ²½λμ΄μλ μ λ©λλ€.
- μ€λͺ
μ μΈ μ΄λ¦ β μ:
GetCustomerById
,ListOrdersByDateRange
λ±κ³Ό κ°μ΄ μμ²νλ μ 보λ₯Ό μ μ€λͺ ν΄μΌ ν©λλ€. - νν° λ° νμ΄μ§ β λ μ§, μν, νμ΄μ§, μ λ ¬ λ± νΉμ 쑰건μ λ§λ κ²μμ μν νλΌλ―Έν°λ₯Ό ν¬ν¨ν μ μμ΅λλ€.
- νλ‘μ μ β λλ©μΈ κ°μ²΄ μ 체λ₯Ό λ‘λνμ§ μκ³ , νμν νλλ§ ν¬ν¨λ DTO λλ λ·° λͺ¨λΈμ λ°νν΄μΌ ν©λλ€.
쿼리 μ ν¨μ± κ²μ¬κΈ°
쿼리 μ ν¨μ± κ²μ¬κΈ°λ νν°, νμ΄μ§ κ°(page, pageSize), 보μ κ·μΉ(μ¬μ©μ κΆν, λ°μ΄ν° κ°μμ±) λ±μ μ λ ₯ νλΌλ―Έν°λ₯Ό κ²μ¦νλ μν μ ν©λλ€. λν FluentValidationμΌλ‘ ꡬνλ©λλ€.
쿼리μμμ μΌλ°μ μΈ μ ν¨μ± κ²μ¬ κ·μΉ
GreaterThanOrEqualTo
λλLessThanOrEqualTo
β λ μ§ λ±μ λ²μ νν°μ μ¬μ©λ©λλ€.Length
β μ΄λ¦μ΄λ μ΄λ©μΌ λ± ν μ€νΈ νν°μ μ¬μ©λ©λλ€.InclusiveBetween
β νμ΄μ§λΉ νλͺ© μμ κ°μ νμ΄μ§ νλΌλ―Έν°μ μ¬μ©λ©λλ€.
쿼리 νΈλ€λ¬
쿼리 νΈλ€λ¬λ 리ν¬μ§ν°λ¦¬λ λ°μ΄ν°λ² μ΄μ€ 컨ν
μ€νΈλ₯Ό μ‘°ννκ³ μ΅μ νλ νλ‘μ μ
μ λ°ννλ μν μ νλ©°, λλ©μΈ μν°ν° μ 체λ₯Ό λ‘λνλ κ²μ νΌν΄μΌ ν©λλ€.
Linoμμλ .Select()
μ κ°μ λ©μλλ₯Ό μ¬μ©νμ¬ λ°μ΄ν°λ₯Ό μνλ DTO νμμΌλ‘ μ§μ λ§€ννλ νλ‘μ μ
λ°©μμ κΆμ₯ν©λλ€. μ΄λ ν¨μ¨μ±κ³Ό μ±λ₯ ν₯μμ λμμ΄ λ©λλ€.
쿼리 결과
Linoμμλ 쿼리 κ²°κ³Όκ° νμ QueryResult
μ λ―Έμ¬κ° λΆμ recordλ‘ ννλ©λλ€.
μ΄ κ·μΉμ μλ΅ μ νμ΄ λͺ©λ‘(νμ΄μ§ ν¬ν¨ μ¬λΆμ κ΄κ³μμ΄)μ΄λ , λ¨μΌ μμΈ νλͺ©μ΄λ μκ΄μμ΄ μ μ©λ©λλ€.
CLIλ‘ μΏΌλ¦¬ μμ±νκΈ°
컀맨λμ λ§μ°¬κ°μ§λ‘, Linoλ λ€μ λͺ λ Ήμ΄λ₯Ό μ 곡ν©λλ€:
lino query new
λ§λ²μ¬λ λ€μ μ 보λ₯Ό μμ²ν©λλ€:
- μλΉμ€ β 쿼리λ₯Ό μμ±ν μλΉμ€μ λλ€.
- λͺ¨λ β ν΄λΉλλ κ²½μ° λλ©μΈ λͺ¨λμ μ§μ ν©λλ€.
- μν°ν° β μΏΌλ¦¬κ° μ°κ²°λ μν°ν° λλ μ 그리κ²μ΄νΈ (μ ν μ¬ν).
- 쿼리 μ΄λ¦ β μ:
GetOrderById
λλListProductsByCategory
.
Linoλ λ€μ νμΌλ€μ μλμΌλ‘ μμ±ν©λλ€:
GetOrderByIdQuery.cs
GetOrderByIdQueryValidator.cs
GetOrderByIdQueryHandler.cs
GetOrderByIdQueryResult.cs
쿼리μ λν μμ±λ ꡬ쑰 μμ
MyApp/ βββ src/ βββ Services/ βββ MyService/ βββ Application/ βββ MyApp.MyService.Application.csproj βββ UseCases/ βββ Orders/ βββ Commands/ | βββ ... βββ Queries/ βββ GetOrderById/ βββ GetOrderByIdQuery.cs βββ GetOrderByIdQueryValidator.cs βββ GetOrderByIdQueryHandler.cs βββ GetOrderByIdQueryResult.cs
κ²°λ‘
Linoμμ Use Cases(Commands λ° Queries)λ₯Ό μ μνκ³ κ΅¬μ‘°ννλ λ°©λ²μ μ΄ν΄ν ν, μ°κΈ°μ μ½κΈ° λ‘μ§μ λͺ ννκ² λΆλ¦¬νμ¬ κ²¬κ³ νκ³ νμ₯ κ°λ₯ν λΉμ¦λμ€ μλ리μ€λ₯Ό λ§λ€ μ€λΉκ° λ κ²μ λλ€. κ°λ° μλλ₯Ό λμ΄κΈ° μν΄ CLIλ₯Ό μ¬μ©νλ, λλ©μΈμ νΉμ μꡬ μ¬νμ λ°λΌ ꡬνμ νμ κ²ν νκ³ μ‘°μ νμΈμ.
λ€μμΌλ‘λ λ°μ΄ν° μ§μμ±, λλ©μΈ μ΄λ²€νΈ λ° μΈνλΌ μλΉμ€ μ²λ¦¬ λ°©λ²μ νꡬνμ¬ μ ν리μΌμ΄μ μν€ν μ² μ 체λ₯Ό ꡬμ±νμΈμ.