Designing Software for Low-Data Realities

Open any popular app and start using it on a slow connection. Watch what happens. Spinners that never resolve. Images that never load. Actions that appear to work until you realize minutes later they did not. Most modern software is designed for conditions that do not describe most of the world.

At Ubora Labs, we design in the opposite direction from the start. Not as a feature, not as an accessibility afterthought, but as a core constraint that shapes every decision we make. This article is about what that actually means when you sit down to build something.

The constraint that changes everything

When you design for unlimited data and fast connectivity, you can be lazy. Fetch everything fresh every time. Never cache. Never queue. Assume the server is always a millisecond away.

When you remove that assumption, the entire architecture of a product has to change. You can no longer treat connectivity as a given. You have to treat it as a resource that might not be available — and design your product to remain useful even when it is not.

The question is not "what does this feature do when connectivity is good?" It is "what does this feature do when connectivity is gone?"

That question, asked consistently across every feature, produces a fundamentally different kind of software.

What offline-first actually means

"Offline-first" is sometimes used loosely to mean "works a little bit when offline." That is not what we mean. Offline-first means the app's default state is to function fully without a connection, and connectivity is treated as an enhancement when it is available, not a requirement.

In practice, for a product like Ubora Écoles, this means:

Data-aware is not the same as data-light

Low-data design is sometimes confused with making apps that look minimal or stripped-down. That is not the goal. The goal is intentionality about what data gets transferred and when.

A data-aware app tracks how much data each operation consumes. It offers users choices about when to sync, when to download media, and what to cache for offline use. It distinguishes between what needs to be current and what can be a few hours old without consequence.

In Ubora Écoles, a grade report does not need to refresh every 30 seconds. A timetable does not need to be re-downloaded every session. By being precise about what data is actually time-sensitive, we can reduce network usage by 60 to 80 percent compared to a naive implementation, without sacrificing any functionality that users actually care about.

Designing for the device, not the ideal

The other side of this constraint is hardware. The median device running our products is not a high-end smartphone bought last year. It is a mid-range Android with limited RAM, limited storage, and a battery that has been cycled too many times.

This changes how you write code. Heavy JavaScript frameworks that are fine on a top-tier device become sluggish and draining on a three-year-old budget phone. Animations that look polished on fast hardware feel janky and battery-hungry on real devices.

We test on the devices our users actually have. Not just in simulators. Real devices, real conditions, real network speeds. The gap between "works in the simulator" and "works in the field" is large enough to kill a product if you do not close it early.

Why this matters beyond Africa

Software designed for data scarcity is, in many ways, better software. It is faster. It is more resilient. It works in basements and on trains and in areas with poor coverage everywhere, not just in places where data is expensive.

The principles we apply building for Africa produce apps that are more thoughtful about resources, more considerate of user agency, and more robust in the face of unpredictable conditions. That is not a consolation prize for building under constraints. It is the product of taking those constraints seriously as design inputs.

The constraint is not the limitation. It is the brief.