Conventions help us not think about unimportant details and let us focus on what matters - what your software should do.
Examples (domain: games):
createGameLoop
- dispatchesGAME_UPDATE
continuoslycreateInputTracker
- tracks keyboard/gamepad input and dispatches eventscreatePlayer
- draws player, tracks input events and handles player interactions with other objectscreateGame
- a general observer which creates instances of all game-related observers (like )
Examples (domain: html5 apps):
createInput
- creates an input element, manages lifecycle, tracks and dispatches events for its instancecreateTextarea
- creates an textarea element... rest is similar to the abovecreateButton
- ... you got the idea
Examples (domain: any arbitrary app in the browser):
createResizeTracker
- attachesresize
handler on the document, dispatchesDOCUMENT_RESIZE
createHTMLEvents
- tracks all events on the document and dispatches either a generic event (example:HTML_EV_ANY
) withpayload
the event name and arguments, or/and also dispatches events which other components can listen to (e.g.HTML_EV_CLICK
,HTML_EV_DRAG_START
,HTML_EV_INPUT
, etc.))createCalculateLandArea
- service-like - accepts an event to request some work done (e.g.LAND_AREA_REQUEST_CALCULATE
) and dispatches back an event when the work is done:LAND_AREA_CALCULATED
with the respective result payloadcreateCanvasDrawing
- contextual controller - listens for events and draws to acanvas
element for a drawing app, for example:BRUSH_STROKE
(with payload of the position and the ),PAINT_FILL
(with payload the position and any other parameters regarding the fill),COLOR_SET_MAIN
- updates the internalstate
to have the main color used in other events.COLOR_SET_SECONDARY
- updates the internalstate
so that tools use that as a secondary color
Examples:
Filename: <root>/common/createInput.ts
// common/createInput.ts
...
export const createInput = obsDispCreator(...)
Filename: <root>/game/createPlayer.ts
// common/createPlayer.ts
...
export const createPlayer = obsDispCreator(...)
When creating obs-disp creators (using obsDispCreator
or when directly adding one with addObsDisp
) store anything that your OD changes to a state
variable
Examples:
Domain: html5 apps (imagine React/Angular)
const createCounter = obsDispCreator(() => {
const state = {
count: 0,
counterEl: null as HTMLElement
}
return {
OBS_CREATE: () => {
// code to initialize the counter
state.counterEl = ...
}
COUNTER_INCR: () => state.count++,
COUNTER_DECR: () => state.count--,
OBS_REMOVE: () => {
// code to remove the counter
// <remove it>
state.counterEl = null
}
}
})
Domain: a tic-tac-toe game
// createTicTacToe.ts
const createTicTacToeGame = obsDispCreator(() => {
// here is our state
const state = {
// here is our state
board: initBoard(),
}
const checkGameWon = () => { /* has access to state */ }
const checkGameLost = () => { /* has access to state */ }
const handleRequestPlaceMove = (args) => { /* has access to state */ }
return {
GAME_REQUEST_PLACE_MOVE: (ev) => {
/* logic to set an O or X on the board, if position is not taken */
handleRequestPlaceMove(ev.payload)
}
...
}
})
const initBoard = () => { /* return a 2d array for the board */ }
// createRenderBoard.ts
const createBoardRenderer = obsDispCreator(() => {
// here is our state
const state = {
boardElements: [] as HTMLElement[]
}
return {
OBS_CREATE: () => {
// initialize the board elements that we draw
state.boardElements = ... // code to create html elements or draw onto canvas or in console
// attach click handlers to dispatch GAME_REQUEST_PLACE_MOVE
},
GAME_WON: () => { ... /* code to handle what happens when the board */},
GAME_LOST: () => { ... },
OBS_REMOVE: () => {
// code to clean up the board, e.g.
state.boardElements.forEach(el => el.remove())
state.boardElements = []
}
...
}
})
// index.ts
createTickTacToeGame()
createBoardRenderer()
Examples: see the checkGameWon
, checkGameLost
, handleRequestPlaceMove
from above.
These functions are accessible only from the OD instance and do not polute the module scope but deal with the state
of the OD.
<work in progress>
Note: you can find real usages on the Usage Examples Page and Repo