Scaling Complexity I
November 14, 2025
Table of Contents
Scaling Complexity I: View Model interfaces#
View model interfaces are your first line of defense in scaling complexity. They significantly improve the robustness of complex UI by defining a clear boundary between view and business logic.
export interface AutocompleteVM {
/** The actual user's input text area */
inputText$: Queryable<string>;
updateInput(text: string, pos: "end" | number): void;
/** Selection affects the autocomplete options */
updateSelection(pos: number, anchor?: number): void;
/** Keyboard navigation affects what is selected */
pressKey(key: "enter" | "up" | "down" | "escape"): void;
/** Options shown below the editor input when non-empty */
options$: Queryable<
Array<{
key: string;
label: string;
selected$: Queryable<boolean>;
click(): void;
}>
>;
}Why#
- Single, tight, typed "view model" interface
- More reliable complex logic impl & UI impl derived from the view model interface
- Faster, full-featured testing without React/DOM
How#
Examples#
Interface
export type TodoItemVM = {
key: string;
text$: Queryable<string>;
completed$: Queryable<boolean>;
toggleCompleted: () => void;
remove: () => void;
};
export type TodoListVM = {
header: {
newTodoText$: Queryable<string>;
updateNewTodoText: (text: string) => void;
addTodo: () => void;
};
itemList: {
items$: Queryable<TodoItemVM[]>;
};
footer: {
incompleteDisplayText$: Queryable<string>;
currentFilter$: Queryable<"all" | "active" | "completed">;
showAll: () => void;
showActive: () => void;
showCompleted: () => void;
clearCompleted: () => void;
};
reset: () => void;
};React Code
Todo List View
export const MainSection: React.FC = () => {
const vm = useTodoVM();
const sectionRef = useRef<HTMLElement>(null);
return (
<section ref={sectionRef} className="todos">
<ul className="todo-list">
<Queryable query={vm.itemList.items$}>
{(items) =>
items.map((item) => (
<li className="state" key={item.key}>
<Queryable query={item.completed$}>
{(completed) => (
<input className="toggle" type="checkbox" checked={completed} onChange={() => item.toggleCompleted()} />
)}
</Queryable>
<label >
<Queryable query={item.text$} />
</label>
<button type="button" className="destroy" onClick={() => item.remove()} />
</li>
))
}
</Queryable>
</ul>
</section>
);
};