Front-end tech leader
Stefano Magni
Cypress integration tests
TypeScript’ Discriminated Unions
Straightforward React components
Explicit State Machines
Ambiguity about what the app does
Ambiguity about data flows
Ambiguity about components
Ambiguity about domain definitions
The intersection among the previous points
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
switch (connectStatus.status) {
case 'notRequestedYet':
case 'failed':
case 'succeeded':
}
break
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
Navigation
Shopify connection status
Admin privileges
The intersection among the previous points
type AppStatus =
| { status: 'showConnect' }
| { status: 'showNonAdminError' }
| { status: 'showSelectOrdersInstructions' }
| // etc.
useEffect(() => {
switch (currentPage) {
case 'connect':
switch (howUserNavigated('connect')) {
// ------------------------------------------------------------------
// SCENARIO: the server redirected the user to the connect page
// ------------------------------------------------------------------
case 'sentFromServer':
switch (connectStatus.status) {
case 'notRequestedYet':
case 'failed':
// when the connect succeeds, this effect is re-triggered
setStatus({ status: 'showConnect' })
break
case 'succeeded':
setStatus({ status: 'showSelectOrdersInstructions' })
break
}
break
// ------------------------------------------------------------------
// SCENARIO: the user navigated directly to the connect page
// ------------------------------------------------------------------
case 'directNavigation':
redirectTo('home') // as a result, this effect is re-triggered
break
}
break
Navigation
Shopify connection status
Admin privileges
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
function createEmailMessage(order: Order) {
if (order.expectedDelivery) {
return `${order.name} will be delivered on ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
type Order = {
name: string
description?: string
at: Location
} & ({
status: 'ready'
} | {
status: 'inProgress'
expectedDelivery: Date
} | {
status: 'complete'
expectedDelivery: Date
deliveredOn: Date
})
type Order = {
status: string
name: string
description?: string
at?: Location
expectedDelivery?: Date
deliveredOn?: Date
}
function createEmailMessage(order: Order) {
switch(order.status) {
case 'ready':
return `${order.name} is at ${order.at}`
case 'inProgress':
return `${order.name} will be delivered on ${order.expectedDelivery}`
case 'complete':
return `${order.name} has been delivered on ${order.deliveredOn}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string | undefined
if (order.expectedDelivery) {
return `${order.name} will be delivered ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string
switch(order.status) {
case 'ready':
return `${order.name} is at ${order.at}`
case 'inProgress':
return `${order.name} will be delivered ${order.expectedDelivery}`
case 'complete':
return `${order.name} has been delivered at ${order.deliveredOn}`
}
}
function createEmailMessage(order: Order) {
// ^? createEmailMessage(order: Order): string | undefined
if (order.expectedDelivery) {
return `${order.name} will be delivered ${order.expectedDelivery}`
}
if (order.deliveredOn) {
return `${order.name} has been delivered on ${order.deliveredOn}`
}
if (!order.expectedDelivery && !order.deliveredOn) {
return `${order.name} is at ${order.at}`
}
}
function createEmailMessage(order: Order) { /* ... */ }
// ^? createEmailMessage(order: Order): string
const message = createEmailMessage(order)
sendEmail(message)
function createEmailMessage(order: Order) { /* ... */ }
// ^? createEmailMessage(order: Order): string | undefined
const message = createEmailMessage(order)
if(message) {
sendEmail(message)
}
export function RenderOrder() {
const [order, setOrder] = useState<Order | undefined>()
useEffect(() => {
fetch('https://api.yourdomain.com/latest-order')
.then(response => response.json())
.then(order => setOrder(order))
}, [])
const onSendEmailClick = useCallback(() => {
if (!order) return
const message = createEmailMessage(order)
if (message) {
sendEmail(message)
}
}, [order])
if (!order) return null
return (
<div>
<p>
{order.name} ({order.status})
</p>
{order.description && <p>{order.description}</p>}
{!order.deliveredOn && order.expectedDelivery && (
<p>Expected delivery: {order.expectedDelivery}</p>
)}
{order.deliveredOn && <p>Delivered on: {order.deliveredOn}</p>}
<button onClick={onSendEmailClick}>Send email</button>
</div>
)
}
export function RenderOrder() {
const [order, setOrder] = useState<Order | undefined>()
useEffect(() => {
fetch('https://api.yourdomain.com/latest-order')
.then(response => response.json())
.then(order => setOrder(order))
}, [])
const onSendEmailClick = useCallback(() => {
if (!order) return
const message = createEmailMessage(order)
if (message) {
sendEmail(message)
}
}, [order])
if (!order) return null
return (
<div>
<p>
{order.name} ({order.status})
</p>
{order.description && <p>{order.description}</p>}
{!order.deliveredOn && order.expectedDelivery && (
<p>Expected delivery: {order.expectedDelivery}</p>
)}
{order.deliveredOn && <p>Delivered on: {order.deliveredOn}</p>}
<button onClick={onSendEmailClick}>Send email</button>
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type Props = {
order: Order
}
export function CompleteOrder(props: Props) {
const { order } = props
if (order.status !== 'complete') return null
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type Props = {
order: Order
}
export function CompleteOrder(props: Props) {
const { order } = props
if (order.status !== 'complete') return null
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type CompletedOrder =
Extract<Order, { status: 'complete' }>
type Props = {
order: CompletedOrder
}
export function CompleteOrder(props: Props) {
const { order } = props
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
export function RenderOrder() {
const fetchStatus = useFetchOrder()
if (fetchStatus.status === 'loading')
return <p>Loading...</p>
const order = fetchStatus.order
switch (order.status) {
case 'ready':
return <ReadyOrder order={order} />
case 'inProgress':
return <InProgressOrder order={order} />
case 'complete':
return <CompleteOrder order={order} />
}
}
type CompletedOrder =
Extract<Order, { status: 'complete' }>
type Props = {
order: CompletedOrder
}
export function CompleteOrder(props: Props) {
const { order } = props
const { name, description, deliveredOn } = order
return (
<div>
<OrderHeading name={name} description={description} />
<p>Delivered on: {deliveredOn}</p>
<SendEmailButton order={order} />
</div>
)
}
Tests - What data the app exchanges with the server
React components - App's structure
Tests - What the app does
State Machine - How the app works
Types - Domain-related knowledge
Front-end tech leader
Stefano Magni