Jump to content

Domain Driven Design, F# and Types

Оцени ову тему


Juanito

Препоручена порука

Да поделим са заинтересованима видео који ми се допао.

https://skillsmatter.com/skillscasts/4971-domain-driven-design-with-scott-wlaschin

Предавач користи F#, али оно што говори је применљиво у другим језицима као што су Haskell, Scala, Swift итд. Мада, сад кад је .NET отворен, F# постаје све занимљивија опција за серверски код. Чова такође пише занимљиве текстове на сајту http://fsharpforfunandprofit.com/

Link to comment
Подели на овим сајтовима

Ево га један чест случај где је овакав приступ супер. Замислите да имате неки овакав web api који враћа неки JSON:

https://somecoollibrary.com/search?query=author:zvonko_m+AND+title:natural_law+AND+subject=libertarianism&sortBy=relevance

Погледајмо овај 'query' параметар. Могуће је навести аутора, наслов, област, датум објављивања итд. Такође је могуће правити сложеније упите користећи AND, OR и ANDNOT операторе. Елегантно решење, користећи алгебарскe типoве, је следеће:

class Box<T> {
    let value: T
    init(_ value: T) { self.value = value }
}

enum Result<T> {
    case Success(Box<T>)
    case Error(NSError)
}

enum SubjectName : String {
    case Libertarianism = "Libertarianism"
    case Comunism = "Comunism"
    case ComputerScience = "Computer Science"
}

enum SearchQuery {
    case Title(String)
    case Author(String)
    case Subject(SubjectName)
    case Published(NSDate)
    case AND(Box<SearchQuery>, Box<SearchQuery>)
    case OR(Box<SearchQuery>, Box<SearchQuery>)
    case ANDNOT(Box<SearchQuery>, Box<SearchQuery>)
}

extension SearchQuery {
    func construct() -> Result<String> {
        // TODO: Do the pattern matching in order to validate and construct the string, or report an error.
    }
}

'Box' класа нам треба зато што Swift компајлер још увек нема имплементиране рекурзивне value типове. Eквивалентан F# код je још елегантнији и краћи. Како конструишемо query?

let query1: SearchQuery = .Author("zvonko_m")
let query2: SearchQuery = .Title("natural_law")
let compoundQuery: SearchQuery = .AND(Box(query1), Box(query2))
let queryString = compoundQuery.construct()

Није лоше за овако мали упит, али шта ако има ”ово AND оно OR онотамо ANDNOT овоовде” и ко зна шта још? Ајде што имамо ону 'Box' класу, потреба за њом ће вероватно нестати у наредним верзијама (компајлер би могао да одради то паковање и отпакивање за нас). Горе је то што бисмо имали гомилу угнежђених израза. Решење је у операторима:

infix operator &&& { associativity left precedence 150 }
func &&&(lhs: SearchQuery, rhs: SearchQuery) -> SearchQuery {
    return .AND(Box(lhs), Box(rhs))
}

infix operator ||| { associativity left precedence 140 }
func |||(lhs: SearchQuery, rhs: SearchQuery) -> SearchQuery {
    return .OR(Box(lhs), Box(rhs))
}

infix operator &&! { associativity left precedence 130 }
func &&!(lhs: SearchQuery, rhs: SearchQuery) -> SearchQuery {
    return .ANDNOT(Box(lhs), Box(rhs))
}

Сада (благо побољшани) хипотетички упит са почетка овог поста изгледа овако:

let query: SearchQuery = .Author("zvonko_m") &&& .Title("natural_law") &&& .Subject(.Libertarianism) &&! .Subject(.Comunism)
let queryString = query.construct()

Нема више потребе за експлицитном кутијом и угнежђивањем, оператори то раде за нас.

 

Овај тип 'Result<T>' садржи резлтат неке операције или грешку. Овако огољен,  без помоћних функција и оператора, може бити мало незграпан за коришћење, јер сваки пут мора да се ради pattern matching или if блок, да би се видело да ли је у питању успех са резултатом или грешка. Ако имамо више операција, или операције које зависе једне од других, ту може да настане пакао угнежђених блокова. Међутим, овај тип је оно што математичари називају монадом, тако да можемо дефинисати оператор који уланчава више операција које враћају 'Result<T>', те да ако било која од њих омане, омануће читав ланац и пријавиће грешку која се догодила. Рецимо овако:

let complicatedOperation = step1 >>== step2 >>== step3 >>== step4

F# за исту сврху користи Computation Expressions, не помињући уопште монаде, што је вероватно паметан избор. Горњи оператор је еквивалентан функцији 'Bind' у F#.

Link to comment
Подели на овим сајтовима

Придружите се разговору

Можете одговорити сада, а касније да се региструјете на Поуке.орг Ако имате налог, пријавите се сада да бисте објавили на свом налогу.

Guest
Имаш нешто да додаш? Одговори на ову тему

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Чланови који сада читају   0 чланова

    Нема регистрованих чланова који гледају ову страницу

×
×
  • Креирај ново...