The art of explicit
User interfaces
Farzad Yousefzadeh
@FARZAD_YZ
@FARZAD_YZ
✈️ ENGINEER
💻 ENGINNER

Living in
🇫🇮
@
User interface is
Challenging
Command line
Direct manipulation ui
Why User Interface is hard?
Run on different platforms
Platforms are different
Partial standards
Styling challenges
SOurces of Data
Unpredictable consumers
Accessibility
internationalization
State management
Renderer = View
(State)
Renderer = View
(State)
Behavior?
Explicitness
Predictable
Explicit state
Renderer = View
(State)
Explicit UI
Own mistakes in state management
IMplicit states
before fetching
after fetching
isFetching: true

Booleans don't inherent any meaning.
Jeremy Fairbank elm-conf 2017
Use booleans when you need both of the sides
Use multiple booleans when you need all of the permutations
type FetchingState =
| BeforeFetching
| Fetching
| FetchedValidData
| FetchedCorruptedData
| FetchedError
Missing states
Error
Empty
First class edge cases
Conflicting states
type LayoutProps = {
main?: boolean;
header?: boolean;
right?: boolean;
}
type LayoutProps = {
main?: boolean;
header?: boolean;
right?: boolean;
}
<Layout main />
<Layout header />
<Layout right />
8
3
type LayoutType =
| Main
| Header
| Right
<MainLayout />
<HeaderLayout />
<RightLayout />

optional
Boolean
type LayoutProps = {
main?: boolean;
header?: boolean;
right?: boolean;
}
const layoutProps = {
isMain: false,
isHeader: false,
isRight: false
}
Mutually Exclusive
Mutually exclusive props
Guards
Unnecessary tests
Uncertainty
Limited values
Complexity growth
Priority will matter
isLoading: boolean
isMain: true;
isHeader: true;
derived states
const ArticleList = ({list}) => {
return (
{list.length === 0 ? <p>Empty list</p> : null}
)
}
const Article = ({ article }) => (
<div>
{article.pictures.length ? (
<>
<Picture src={article.pictures[0].url} />
<PictureCaption>{article.pictures[0].caption}</PictureCaption>
</>
) : null}
</div>
);
switch(event.type) {
case "SET_CHECKING":
return {
...state,
checking: true,
error: undefined
}
case "CHECK_SUCCESS":
return {
...state,
checking: false,
status: event.payload
}
case "CHECK_FAILURE":
return {
...state,
checking: false,
error: event.payload
}
default:
return state;
}
{
status: undefined,
checking: false,
error: undefined
}
type HealthCheckState
=
| Idle
| Checking
| Success status
| Failure error
{
status: undefined,
checking: false,
error: undefined
}
Grouping relevant data

Event Driven
I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.
The big idea is "messaging"
Problematic
conventions
Event, Action
document.getElementById("button")
.addEventListener("click", e => {
// Run side effects
})
dispatch({ type: "authorize_session" });
function authorizeHandler(state) {
if (state.session.isLoggedIn) {
dispatch({ type: "session_authorized" });
} else {
if (isSessionValidForRefreshing(state.session.lastLoggedIn))
{
dispatch({ type: "retry_session" });
} else {
if (state.session !== undefined) {
dispatch({ type: "session_logout" });
}
}
}
}

High cyclomatic complexity
hard to detect and separate "similar states".
Event handlers
renderers
login()
logout()
checkout()
addToCart()
LoginView
LogoutView
CheckoutView
CartView
Separately modeled
As HUMANS...
FSM
& Statecharts
FSM(State + Event) => NextState + SideEffects
Purity vs Idempotence
Reducing logic
Finite state machines
Guarding vs Not Allowing
Event->Action
Event+State->Action
Travel To Past
vs
Travel to Past & Future
Idiomatic reducing logic
Idempotence
Treat UI as a whole entity
Still keep logic idempotent
+
FSM + Actor model
MAKE IMPOSSIBLE STATES IMPOSSIBLE
Making Impossible States Impossible by Richard Feldman
MAKE IRRELEVANT DATA UNAVAILABLE
DO NOT TEST SOMETHING THAT IS NOT SUPPOSED TO HAPPEN
TESTING IS GOOD.
IMPOSSIBLE IS JUST BETTER.
Making Impossible States Impossible by Richard Feldman

simple user interfaces are easy to construct, it is the complx ones that need to be designed.
Constructing the user interface with statecharts / Ian Harrocks
