AI-Friendly Frameworks: As Abstraction Moves Up, How Can Verification Keep Pace?

Coding agents are changing how we write software, and they are quietly reshaping the criteria we use to judge frameworks and tools.

As AI coding becomes widespread, more and more developers lean toward one view: imperative frameworks like UIKit may suit coding agents better than SwiftUI. The reasoning is intuitive. UIKit’s logic is direct and explicit: create objects, set properties, add them to the hierarchy, build constraints. Every step acts on a concrete entity. SwiftUI, by contrast, tucks much of its implementation detail behind declarative syntax, where state, environment, identity, layout, and rendering jointly determine the final result. When the output drifts from what was expected, an agent is left facing a black box, working backward from limited external symptoms to figure out what actually happened inside.

The conclusion seems natural: AI handles low-level APIs close to the implementation better than highly abstract frameworks.

I don’t think the problem lies in abstraction itself. It lies in the other half of the work we left undone after abstracting: observation and verification. When abstraction hides the underlying details, we have to rebuild, at the new level, the means to pin down and verify our intent.

Does AI Really Prefer UIKit?

Suppose we need to switch screens based on login state. SwiftUI expresses this intent very directly:

Swift
if session.isAuthenticated {
    ContentView()
} else {
    LoginView()
}

The developer describes what they want, not the concrete operations needed to get there.

In an imperative UI framework, the same requirement usually means managing the creation, replacement, and lifecycle of views or view controllers yourself, and responding to state changes explicitly.

For a coding agent, imperative code is not inherently simpler. It’s just that UIKit’s UIView, frames, constraints, view hierarchy, and CALayer are all concrete objects, so when something goes wrong, there are plenty of ways to inspect and intervene.

In SwiftUI, a declaration roughly passes through the following stages (a conceptual sketch, not a strict execution order):

Text
View Declaration
       ↓
State / Observation
       ↓
Environment
       ↓
Identity
       ↓
Transaction
       ↓
Layout
       ↓
Rendering

SwiftUI frees developers from these details. The cost is that, at SwiftUI’s current level of abstraction, we can’t always get sufficiently transparent runtime information. Once the underlying information is no longer visible, the observation and verification techniques built on top of it stop working too.

We often say abstraction exists to “hide complexity,” but that isn’t its essence. What abstraction really does is let us understand, express, and manipulate problems at a higher semantic level. Once the underlying implementation is hidden, observability and verifiability have to be rebuilt on the new layer of abstraction.

This predicament didn’t begin with AI; coding agents simply amplify it. The claim that “UIKit suits agents better” isn’t baseless today. It does reflect SwiftUI’s shortcomings in verification. But blaming abstraction itself isn’t fair.

AI Needs a Stable Model

SwiftUI’s modifier order is a good place to start.

When developers first encounter SwiftUI, many developers treat modifier order as a collection of scattered rules of thumb: this one must come first, that one only works last, and swapping them changes everything. If all we end up with is dozens of rules learned by rote, humans and agents alike get bogged down chasing special cases.

Look one layer deeper, though, and some modifier-order problems can be reduced to transformation order and understood through matrix composition.

In Modifier Order Is Matrix Order, Mihaela Mihaljević Jakić reinterprets the composition order of offset, rotationEffect, and scaleEffect in terms of matrix transforms: the modifier closest to the view acts on the content first. This matches exactly how matrices compose in Core Graphics, only read in the opposite direction. What looked like scattered rules of thumb becomes a system of rules you can derive.

Text
Rules of thumb
     ↓
Transformation Model
     ↓
Derivable results

This is the key step toward an AI-friendly abstraction: not lowering the level of abstraction, but giving the abstraction itself a clear, stable, and as-derivable-as-possible semantic model. Memorizing rules is easy for an agent, but a model it can reason through rigorously is far more reliable than special cases stuffed into its context.

Still, a derivable model only tells the agent how things should work. The real question is how the agent can confirm it actually got things right.

Mihaela’s article already sketches an answer. She didn’t stop at the matrix derivation. She rendered multiple modifier chains with ImageRenderer, measured the output pixel by pixel, and compared it against the predicted values. That measured comparison caught a hidden rule the algebraic model missed: offset snaps the translation (or offset value) to the pixel grid first, and a subsequent scaleEffect then magnifies that rounding error along with everything else. A deviation this small is nearly impossible to catch by eye or by reasoning alone. The model supplied the expectation; only measurement at the end of the pipeline exposed the blind spot outside the theory.

From Probabilistic Judgment to Deterministic Evidence

Describing a model clearly in documentation already helps an agent reason better. But to confirm that an implementation meets expectations, we need to connect the model to executable checks.

If verification is handed entirely to another probabilistic model, we are only using new uncertainty to vouch for old uncertainty. What a coding agent lacks is not one more probabilistic guess, but objective evidence that gives a definite answer to a specific question. Such evidence may not prove the whole system correct, but it at least moves part of the code beyond “looks fine to me.”

Compilers, validators, unit tests, and snapshots are the deterministic anchors in this process.

These tools verify at different levels. Compilers and static validators check rule contracts: whether APIs are used legitimately and whether dependencies hold. Tests and snapshots declare expected results, pinning down our concrete expression of intent. Take “switch screens based on login state”: as test cases, it becomes asserting the login screen when signed out, the content screen when signed in, and a return to the login screen after signing out. With expectations this explicit, an agent has something to check against, item by item.

Rules have to be distilled, and expectations have to be written down; tools can’t decide these for us out of thin air. But once they are clearly expressed, tools can pinpoint, within their coverage, whether an implementation has drifted. Intent varies from one business to another and can only be defined by people; rules, however, are often general and can be captured and reused. So rather than endlessly stuffing knowledge into prompts, the more durable path is to turn general knowledge into executable tools.

From Knowledge to Tool

SwiftFairy is a representative attempt.

Instead of cramming a mass of SwiftUI pitfalls into an agent’s context, it organizes that expertise in an external tool. The tool statically parses code and declarations locally, builds a partial graph of the project, matches it against declarative rules, and returns findings, explanations, and fixes to the agent.

The check involves no LLM at all. Given the same code context, the results are repeatable and deterministic. Expert knowledge thus becomes a callable evaluator: the agent doesn’t need to memorize rules to ensure code quality. It can call the tool after generating code, get concrete feedback, and correct course based on the guidance. More importantly, SwiftFairy doesn’t ask developers to retreat to UIKit; it performs structural checks at SwiftUI’s own semantic level.

InnoDI is an example along a different dimension. As a Swift dependency injection framework, its design shows distinctive value in the AI era.

Compared with approaches like Point-Free’s swift-dependencies, which propagate dependencies implicitly through context, InnoDI can even look a bit verbose at first:

Swift
@DIContainer
struct AppContainer {
    @Input var baseURL: String

    @Provide(.shared, APIClient.self, with: [\Self.baseURL])
    var apiClient: APIClient
}

It abstracts manual, multi-level initializer wiring into an explicit declaration of the dependency graph. For human developers, this DSL isn’t necessarily more intuitive than handwritten initializers, and it adds cognitive overhead.

But its value lies precisely in its closed verification loop: macros catch local errors at expansion time, a build plugin validates the cross-file dependency graph before compilation, and a command-line tool handles global analysis. As implementation details are abstracted away, verification is rebuilt at the new layer of abstraction.

With its accompanying Agent Skill, an agent can look up API rules on demand, while the macros and build plugin provide deterministic compile-time feedback on what it generates. For an agent, how good an abstraction is depends not only on how concise it is to write, but on how clear its relationships are, whether its constraints can be checked by machines, and whether it produces clear diagnostics when something goes wrong.

Abstraction and Verification Should Move Up Together

Back to UIKit versus SwiftUI.

SwiftUI’s current pain point comes largely from abstraction moving ever upward while the matching means of observation and verification haven’t kept pace. When results deviate from expectations, users easily end up feeling powerless in front of a black box.

If the two could move up together, the picture would change completely.

SwiftUI doesn’t need to fall back to UIKit. What it needs is inspection, diagnostics, and verification at its own level. Self._printChanges() and the SwiftUI Instrument in Xcode are steps in this direction, but there is still a long way to go before we have a toolchain that agents can invoke directly and that returns structured feedback.

So when judging whether a framework or tool is AI-friendly, the core may lie in a few dimensions that used to get little emphasis:

  • Does it have a stable, derivable semantic model?
  • Does it offer observability that matches its level of abstraction?
  • Can its key rules and constraints be verified by deterministic tools?

When Frameworks Are No Longer Used Only by Humans

For decades, frameworks and APIs have been designed with human developers in mind. Developer ergonomics focused on intuitiveness, conciseness, low cognitive load, and a smooth learning curve.

These standards still matter. But as coding agents become major writers and maintainers of code, we will need a new dimension of trade-offs: agent ergonomics.

The two don’t necessarily conflict. In some scenarios, though, to gain global verifiability and determinism, we may have to give up some of the casual, “just write it” freedom of traditional development. And once agents are involved, the cost of committing to stricter structure can often be largely absorbed by automated tools.

Clear semantics, stable models, strong typing, precise diagnostics, and deterministic validation have always been qualities that good software engineering pursues. AI simply gives them more pressing practical relevance.


BTW: Take a look at the Skills you use or write. If their main value is supplying the model with general knowledge already available on the public web, that value will depreciate quickly as base models improve. What remains hard to replace is project-specific contextual constraints and decision logic.

The documentation in a Skill should act more like a “glue language” for LLMs: rather than just pouring in knowledge, it guides the model to find and call the right tools, connecting human intent to a closed feedback loop that can be observed, verified, and corrected. The Skills least likely to be replaced by growing model capabilities are usually those that firmly wire concrete constraints into Tools and Feedback Loops.

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now