Show it running: why every Existence package ships with a working demo.
A package is not finished when it builds. It is finished when a real app runs on it. Here is the stubborn habit that lets a small team keep shipping on one shared foundation.
There is a quiet moment in building any shared package when the code compiles, the tests you thought to write are green, and it is tempting to call it done. We have learned, more than once, that this moment is a small lie. A package is not finished when it builds. It is finished when a real app runs on it, and a person who did not write it can pick it up in an afternoon and ship something.
Existence is a small team shipping a growing family of apps on one shared foundation. The only way that arithmetic works is if every capability we build once can be dropped into the next app without a meeting, a migration guide, or a nervous phone call. So we made a rule that sounds almost too simple to matter: nothing joins the foundation until it has proven itself inside a working example app. Not a snippet in a README. A running app you can launch.
Why "done" is the most expensive word we use
The trouble with "done" is that it usually means "done from where I am standing." The author of a package holds the whole model in their head: which method to call first, what the nullable field really means, why the initialisation order is the way it is. To them the code is obvious, because obviousness is just familiarity wearing a disguise. Hand the same package to the next engineer, or to the same engineer three months later, and every invisible assumption becomes a question. Questions cost time, and time is the one resource a bootstrapped team cannot print.
An example app is how we force the assumptions out into the open while they are still cheap to fix. You cannot fake your way through wiring e_core_notifications into a real screen with real deep links. Either the deep link resolves and the notification opens the right view, or it does not. The demo does not care how confident you felt.
A package that has never been used is not a capability. It is a hypothesis with good intentions.
The example app is the acceptance test
When we scaffold something like e_core_ads or e_core_localisation, the example app is not the last step, tacked on once the interesting work is over. It is the acceptance test, and we treat it as a first-class deliverable. The rule is blunt: if the capability cannot be demonstrated end to end in the example app, the capability is not real yet, no matter what the code coverage says.
This flips the usual order of things. Instead of writing a package and hoping it is usable, we write toward a usable moment and let that pull the design into shape. A demo that has to display an ad, translate a screen, or fire a scheduled notification is a stubborn, honest customer. It refuses to accept an interface that only makes sense to its author.
What a good demo forces you to decide
The value of building the example app early is not the app itself. It is the set of decisions it drags out of the shadows, the ones you would otherwise defer until they are expensive. Every time we wire a new package into a real demo, it forces answers to questions like these:
- What does the first line of setup look like? If it takes more than a few lines to get a sensible default running, the surface is too complicated and we simplify it now, not later.
- What happens when the network is not there? A demo on a real device, on a real train, in a real dead spot, answers this honestly.
- Where does configuration belong? Building the example reveals which knobs the host app truly needs and which ones were only there to make us feel thorough.
- Can the network or provider be swapped? A layer is only worth the name if the thing underneath it can change without the app noticing.
None of these questions are answered by unit tests alone, because unit tests confirm that the parts you imagined work the way you imagined them. The demo tests the part you did not imagine: the join between your package and everything around it.
Tests are the second reader
If the example app is the customer, the test suite is the second reader, the one who arrives long after the original author has moved on. We ship every core package with its own tests and a README that a stranger can follow, and we do not consider this overhead. It is the interest payment we make now so we do not pay the principal later, in a debugging session at the wrong hour.
Three artefacts travel with every capability before it earns a place in e_core_package: the code, a test suite that exercises it, and an example that runs it in the open. Miss any one and the package is not done, it is merely written. The distinction has saved us more evenings than we can count.
The quiet compounding
The honest reason we work this way is not virtue. It is leverage. A small team cannot out-hire a big one, so it has to out-compound it. Every capability that ships with a demo and a test is a capability the next app inherits for free, and the app after that, and the one we have not thought of yet. The cost is paid once, by the person closest to the problem, at the moment they understand it best.
It is not glamorous work. Writing an example app for a package you already believe works feels, in the moment, like paperwork. But paperwork that stops a future question from ever being asked is the difference between a foundation you can build on and a pile of code you have to keep explaining. We would rather explain it once, to a demo that cannot be charmed, and then never again.
So the rule stays. Show it running, or it is not done.