Skip to content

Instantly share code, notes, and snippets.

@laser
Last active February 10, 2016 18:30
Show Gist options
  • Save laser/e53e7d6374ed1e1aef22 to your computer and use it in GitHub Desktop.
Save laser/e53e7d6374ed1e1aef22 to your computer and use it in GitHub Desktop.
Yay, Haskell.

The New World Order

Things That I Really Liked

This section is never as exciting as the gripe-section; I'll keep it brief:

  • System collaborators instantiated centrally
  • Wrapping persisted values in Stored type
  • Great take on decoupling notion of request processing and response-creation from Scotty

Things That Made Me Go Hmm

https://www.youtube.com/watch?v=XF2ayWcJfxo

Where did...?

newtype Wrappers on Everything

Concerns:

Recommendation:

The Tale of Three Developers

Concerns:

There exist in our system three different Developer types and three sets of newtype wrappers for their fields' types. This requires that we map between types (Developer) and their fields (FullName, MailboxSpec, etc.) as we move between Web/Service/Persistence and back.

Each "layer" knows how to map their type TO the lower layer:

  • Web knows how to map Web -> Service
  • Service knows how to map Service -> Persistence

Some layers know how to map to their type FROM the lower layer, too:

  • Service knows how to map Persistence -> Service
  • Web knows how to map Service -> Web

Recommendation:

  • Preserve system-edge types (DeveloperSpec and Developer in Web)
  • Combine Service and Persistence types into one set of DeveloperSpec and Developer

Examples:

Web

data Developer = Developer {
  devFullName :: FullName,
  devEmailAddress :: Mailbox
} deriving (Show, Eq)

Persistence

data Developer = Developer {
  devPublicId :: Id,
  devFullName :: FullName,
  devEmailAddress :: MailboxSpec,
  devUsername :: Username,
  devPassword :: Maybe Password
} deriving (Show, Eq)

Service

data Developer = Developer {
  devFullName :: FullName,
  devEmailAddress :: MailboxSpec
} deriving (Show, Eq)

Responsibilities of app/Main.hs

Questions:

  • When would I put Scotty-related calls (i.e. did <- param "id" here) in mkScotty versus the top-level auxiliary functions like postToDevelopers and getToDeveloper?
  • Why is the REFRESH_TOKEN / HTTP 401 logic in app/Main.hs instead of CJ.DeveloperRegistry.Web.Handler? Aren't we to treat app/Main.hs as a dumb bridge between Web.Handler and Scotty? I see some authorization being done Web.Handler.

Recommendations:

  • Modify mkScotty implementation to map routes to request-handlers and centralize all other Scotty interactions (param parsing, header reading, decoding) into those functions
  • Move everything else (e.g. refresh token-checking and response-code creation) into Web.Handler

Error Handling in the Future

Questions:

  • How will this design accomodate for handling synchronously-thrown exceptions (say, PK violations)?
  • How will this system convert between service errors and HTTP responses?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment