This section is never as exciting as the gripe-section; I'll keep it brief:
- System collaborators instantiated centrally
- Wrapping persisted values in
Storedtype - Great take on decoupling notion of request processing and response-creation from Scotty
https://www.youtube.com/watch?v=XF2ayWcJfxo
- Where did developer creation-validation go?
- Where did bcrypt go?
- Where did the refresh token-creation logic go?
Concerns:
- All constructors are exported
- The underlying representation is used throughout the codebase (see: here, here, here, etc.)
- Results in much wrapping and unwrapping
Recommendation:
- Read "Newtypes Aren't as Cool as You Think" by J. DeGoes
- Write smart constructors and stop exporting the dumb constructor
- or... stop using
newtypefor now
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:
data Developer = Developer {
devFullName :: FullName,
devEmailAddress :: Mailbox
} deriving (Show, Eq)
data Developer = Developer {
devPublicId :: Id,
devFullName :: FullName,
devEmailAddress :: MailboxSpec,
devUsername :: Username,
devPassword :: Maybe Password
} deriving (Show, Eq)
data Developer = Developer {
devFullName :: FullName,
devEmailAddress :: MailboxSpec
} deriving (Show, Eq)
Questions:
- When would I put Scotty-related calls (i.e.
did <- param "id"here) inmkScottyversus the top-level auxiliary functions likepostToDevelopersandgetToDeveloper? - Why is the
REFRESH_TOKEN/ HTTP 401 logic inapp/Main.hsinstead ofCJ.DeveloperRegistry.Web.Handler? Aren't we to treatapp/Main.hsas a dumb bridge betweenWeb.Handlerand Scotty? I see some authorization being doneWeb.Handler.
Recommendations:
- Modify
mkScottyimplementation 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
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?