Category pattern

Composition is the essence of programming…

The composition is a style of development to build a new things from small reusable elements. There is a challenge with standard Golang HTTP package. It implements low-level interface, which requires boilerplate code, and absence of advanced requests compositions.

https://assay.it implements Golang SDK. This SDK inherits an ability of pure functional languages to express communication behavior by hiding the networking complexity using category pattern. This pattern helps us to compose a chain of network operations and represent them as pure computation, build a new things from small reusable elements. This pattern is well know in functional programming languages such as Haskell and Scala but it is a new thing for Golang.

Background

The category theory formalizes principles that help us to define own abstraction applicable in functional programming through composition. The composition becomes a fundamental operation: the codomain of 𝒇 be the domain of π’ˆ so that the composite operation 𝒇 β—¦ π’ˆ is defined.

A category is a concept that is defined in abstract terms of objects, arrows together with two functions composition β—¦ and identity π’Šπ’…. These functions shall be compliant with category laws

  1. Associativity : (𝒇 β—¦ π’ˆ) β—¦ 𝒉 = 𝒇 β—¦ (π’ˆ β—¦ 𝒉)
  2. Left identity : π’Šπ’… β—¦ 𝒇 = 𝒇
  3. Right identity : 𝒇 β—¦ π’Šπ’… = 𝒇

The category leaves the definition of object, arrows, composition and identity to us, which gives a powerful abstraction!

IO Category

A composition of HTTP primitives within the category are written with the following syntax:

assay.Join(arrows ...assay.Arrow) assay.Arrow

Here, each arrow is a morphism applied either to protocol to results of I/O. The implementation defines an abstraction of the protocol environments and lenses to focus inside it. In other words, the category represents the environment as an β€œinvisible” side-effect of the composition. The example definition of HTTP I/O within the category becomes

assay.Join(
  http.Join(
    ΓΈ...,         // > GET / HTTP/1.1
    ΓΈ...,         // > Host: assay.it
    ΓΈ...,         // > Accept: text/html

    Ζ’...,         // < HTTP/1.1 200 OK
    Ζ’...,         // < Server: ECS (phd/FD58)
  )
)

Symbol ΓΈ is an convenient alias to writer morphism that focuses inside and reshapes HTTP protocol request. The writer morphism is used to declare HTTP method, destination URL, request headers and payload.

Symbol Ζ’ is an convenient alias to reader morphism that focuses into side-effect, HTTP protocol response. The reader morphism is a pattern matcher, is used to match HTTP response code, headers and response payload.

The SDK also helps us to declare our expectations on the response. The evaluation of β€œprogram” fails if expectations do not match actual response.

The composition is one of major reason why we deviate from standard Golang HTTP interface. Instances of assay.Arrow type are composable β€œpromises” of HTTP I/O. The composition of 𝒇 β—¦ π’ˆ ⟼ assay.Arrow leads results of same type and so on.

assay.Join(
  http.Join(/* ... */),
  http.Join(/* ... */),
)

Essentially, the quality assessment is just set of assay.Arrow functions - Behavior as a Code in other words.

func MyFoo() assay.Arrow {
  return http.Join(/* ... */)
}

func MyBar() assay.Arrow {
  return assay.Join(
    http.HTTP(/* ... */),
    http.HTTP(/* ... */),
  )
}