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
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
newtype
for 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) inmkScotty
versus the top-level auxiliary functions likepostToDevelopers
andgetToDeveloper
? - Why is the
REFRESH_TOKEN
/ HTTP 401 logic inapp/Main.hs
instead ofCJ.DeveloperRegistry.Web.Handler
? Aren't we to treatapp/Main.hs
as a dumb bridge betweenWeb.Handler
and Scotty? I see some authorization being doneWeb.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
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?