When Devices Changed Relationships Instead of Layouts
The interface couldn’t keep up with context
The first article in this series focused on ToDoView and the growing number of relationships accumulating around a task. Notes influenced context. Due dates influenced reminders. Reminders influenced notifications. NanoDos influenced progress. What initially appeared to be individual features gradually revealed themselves as connected parts of a larger system.
The next challenge emerged once that system stopped living in a single place.
At the beginning of the rebuild, I assumed multi-device support would primarily be a presentation problem. The task itself already existed. The supporting functionality already existed. The responsibility now was adapting those experiences to different screens, interaction models, and usage patterns. Every platform introduces constraints, but those constraints are generally visible. Screen size changes. Input methods change. Available space changes. The challenge appeared understandable because it appeared measurable.
That assumption survived exactly long enough to become inconvenient.
The issue was not that different devices required different layouts. That was expected. The issue was that the same task began behaving differently depending on where it was encountered. The task remained unchanged, yet the user’s relationship to that task shifted considerably between devices and surfaces.
A task viewed inside the primary application exists within a relatively rich environment. Context is available. Supporting information is available. Navigation is available. A task viewed elsewhere often arrives stripped of much of that supporting structure. Information becomes more selective. Decisions become more immediate. Attention becomes more limited. The challenge is no longer presenting everything. The challenge becomes deciding what deserves to survive the transition.
This forced me to ask a question I had not anticipated at the beginning of the rebuild.
How much information does a task actually need?
The answer proved less obvious than expected because every feature felt important when considered independently. Due dates matter. Reminders matter. Tags matter. Notes matter. NanoDos matter. Progress matters. Yet the moment a task leaves its primary environment, difficult decisions begin appearing. Which information is essential? Which information is contextual? Which information is helpful? Which information becomes noise?
Those questions repeatedly exposed assumptions hiding inside the product.
The assumption that more context is always beneficial.
The assumption that information hierarchy is universal.
The assumption that visibility and usefulness are synonymous.
None survived particularly well.
The more I worked across surfaces, the more apparent it became that usefulness often emerges through omission rather than inclusion. Features compete for attention. Information competes for visibility. Relationships compete for space. What feels comprehensive in one environment can feel overwhelming in another. What feels efficient in one environment can feel incomplete elsewhere.
The interesting part is that none of these problems originated from individual features. They emerged from the relationships between those features. A due date becomes more important once reminders exist. Reminders become more important once notifications exist. Progress becomes more important once NanoDos exist. Every new capability changes the relative importance of existing capabilities.
The product became increasingly interconnected.
As that happened, adaptation stopped being a question of layout and became a question of preserving relationships. The challenge was no longer determining where information should appear. The challenge was determining which relationships needed to survive as the task moved between contexts and which could safely disappear without weakening the experience.
private var usesRegularWidthLayout: Bool {
horizontalSizeClass == .regular
}
private var regularContentMaxWidth: CGFloat {
680
}
private var contentMaxWidth: CGFloat {
usesRegularWidthLayout ? regularContentMaxWidth : .infinity
}Looking back, I think this was the second major challenge to my assumptions. The first emerged when I realized that creating, viewing, and updating a task represented different moments rather than different functions. The second emerged when I realized that the same task could represent different things depending on where it was encountered. The underlying data remained stable. The relationships surrounding that data did not.
By this point, a pattern was becoming increasingly difficult to ignore. Every assumption that seemed self-evident at the beginning of the rebuild became less certain once relationships entered the picture. The code continued behaving correctly. The features continued functioning correctly. Yet completed work kept returning for additional refinement.
At first, I interpreted that as a consequence of complexity.
Testing would eventually suggest a different explanation.

