DraftThis article is currently in draft mode

Scaling Complexity I

November 14, 2025

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>
  );
};