# Building a no-code app builder out of small pure modules, and testing each one on its own

> Source: <https://dev.to/nebosa_company_0edc92e18b/building-a-no-code-app-builder-out-of-small-pure-modules-and-testing-each-one-on-its-own-5aa3>
> Published: 2026-10-19 23:35:54+00:00

I'm a solo founder based in Europe, building an app builder (Appdor) that turns a spreadsheet into a small business app. This post is about how the code is organised, because that choice has mattered more than any framework decision. Appdor is a plain JavaScript single-page app on Vite, with Postgres behind it. There is no UI framework doing the heavy lifting. What does the heavy lifting is a rule I set early.

A feature like "sort and filter rows" or "evaluate a formula" begins as a function (or a small set of functions) that takes data and returns data. No DOM, no network, no globals. It lives in its own folder under `src/` and has a mirrored test file. The thin layer that touches the page is written afterwards, and is deliberately dull.

Two examples from the repo:

`src/formula/`): a tokenizer, a parser, an evaluator and a function registry, each in its own file, plus a dialect layer that translates formulas written for other spreadsheets. Because the evaluator only sees values and a registry, a test can feed it a string and assert on the result. There is also a compiler that turns a subset of formulas into SQL, so the same expression can run on the server when the data is too big to bring to the browser.`src/views/`): sort, filter, group and summarise over an array of records. The grid, the board and the calendar all call the same function and differ only in how they draw the result.
Start with the data structure and the function that transforms it. Write the failing test with a hand-made input. Only then draw anything. When I broke this order, I ended up with logic buried in event handlers that I could only test by clicking.

Set a rule on day one that no file may import from a "god module", and ban "temporary" functions that hold state at module level. Both are cheaper to prevent than to remove.

If you build UI-heavy tools in plain JS, how do you keep logic out of the event handlers? I'd like to compare notes. (Appdor is at appdor.com if you're curious what these modules add up to; it's an early product from one person, with plenty of rough edges.)
