Back to writing

POWER APPS • ARTICLE #1

When a Canvas App Stops Being Simple

And the Questions That Changed How I Build

While building a Canvas App, I started to realise that “Does it work?” was no longer enough.

If I leave this app for six months and come back to it, will I still understand it well enough to safely change it?

And then came the more uncomfortable thought:

What if the person maintaining it next isn't me?

Anyone taking over an unfamiliar application will need time to understand it. But there is a fundamental difference between learning an unfamiliar structure and having to discover whether a structure exists at all.

So the question became:

“How do I make this understandable and maintainable?”

How I got there

I hadn't started with those questions.

When I first began working with Power Apps, my questions were much more immediate: getting the data I needed, transforming it, and making the application behave the way I wanted.

Documentation, tutorials, examples and experiments helped me answer many of those questions.

But as I was building the solution, the questions gradually changed.

The application was not becoming more complex because new requirements kept arriving. Much of that complexity emerged during the implementation of the requirements that were already there.

A requirement that looked simple from the outside could involve data preparation, validation, access rules, temporary state, UI behaviour and several steps of application logic.

Collections helped me manage and transform data. Reusable formulas helped avoid repeating logic. App.Formulas gave that shared logic a convenient place to live.

These were solutions.

But as more of them accumulated, they started creating a different problem.

When understanding became expensive

Nothing was broken.

But understanding the application was becoming increasingly expensive.

To change one piece of logic, I had to trace where it started, what depended on it, what state it changed, and where that state was used afterwards.

Similar code appeared in different places. Temporary and global state started overlapping. Reusable formulas accumulated. App.Formulas, which had started as a convenient home for shared logic, was becoming another source of spaghetti.

Every change required more searching, more remembering and more rereading of code I had written myself.

And that was the part that bothered me.

The application could continue growing this way. I could continue making it work.

But I could also see where that road was going.

The more I looked at what was making the application difficult to reason about, the more one question kept appearing:

Who is responsible for what?

A collection was not inherently a problem. Neither was App.Formulas, a long formula, or logic attached to a control.

The problem was that responsibilities were becoming harder to see.

  • Who owns this state?
  • Who is allowed to change it?
  • How long should it exist?
  • Why is it global?
  • Where should this business rule live?
  • Why does the UI need to know it at all?

The problem was no longer simply how to make individual pieces work.

It was how those pieces should relate to each other.

The tools were part of the constraint

There is an important piece of context here.

I was not designing the solution from an unrestricted Power Platform toolbox. I was working within the environment available to me: Canvas Apps, SharePoint Lists, Power Automate and the standard Microsoft 365 capabilities I had access to.

So the question was not:

“How would I design this solution if I could start from scratch?”

It was:

“How do I make this maintainable with the tools I actually have?”

With unrestricted platform choices, I would not necessarily choose the same architecture for a system of this complexity.

But constraints do not make the underlying business problem disappear.

They become part of the architecture.

From questions to structure

The questions I was now asking were not really specific to Power Apps:

  • Responsibility,
  • Ownership,
  • Scope,
  • Lifetime,
  • Boundaries.

I had encountered the thinking behind them before in traditional software development.

But I did not want to recreate traditional software development inside a Canvas App, or blindly transplant patterns and principles from a different programming model.

Power Apps removes a lot of code.

It does not remove the need to think about responsibility, ownership, scope, lifetime, maintainability.

That distinction became important.

The goal was not to reproduce traditional software architecture inside Canvas Apps.

It was to take the principles that solved the problems I was actually experiencing and adapt them to the platform I was actually using.

So I started experimenting:

  • The UI should express intent rather than own business logic.
  • Logic should have a clear owner.
  • Temporary state should remain temporary.
  • State should live only as long, and as widely, as it actually needs to.
  • If something is global, there should be a reason for it to be global, and someone should clearly own its lifecycle.
  • Business knowledge should not quietly multiply across different parts of the application.
  • Where a single source of truth mattered, there should actually be one.

Power Apps did not force me to create those boundaries.

That meant I had to create and respect them myself.

I did not try to do that by adding abstraction simply because abstraction looked more “professional”.

Some ideas from traditional software development transferred surprisingly well.

Others had to be adapted to the realities of Canvas Apps.

And some were better left behind entirely.

What remained useful was surprisingly practical:

  • clear responsibility and ownership,
  • separation of UI from business logic,
  • controlled state,
  • deliberate scope and lifecycle,
  • a single source of truth where it matters,
  • reusable logic without duplicated knowledge,
  • explicit boundaries between parts of the application.

The structure I eventually started using was not something I found in a single tutorial or designed upfront.

It emerged gradually from building the application, seeing where control was being lost, trying different approaches, discarding some of them, and keeping the ones that made the application easier to reason about.

That became the beginning of the structure I use now.

Because a Canvas App becoming complex does not necessarily mean it has become unmanageable.

But at some point,

“it works” is no longer enough.