Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
159409 stories
·
33 followers

Why Are Big Tech CEOs Writing Long Manifestos About AI?

1 Share
This week Meta CEO Mark Zuckerberg published a 6,500 word open letter titled "The Future is for Everyone". But the BBC is more interested in why big tech executives keep writing manifestos about AI: [Zuckerberg's] vision echoes what AI leaders have expressed in various forms: the product they are building is among the "most important technologies in history." Marc Andreessen, co-founder of early web titan Netscape, perhaps started this trend in 2023 with a 5,000-word essay he called "The Techno-Optimist Manifesto", which argued innovation was the way to solve life's problems... As the International Monetary Fund warns AI could affect nearly 40% of jobs and worsen global financial inequality, Zuckerberg says he believes there will be an abundance of jobs in the future. "I do not understand why anyone who believes that AI will eliminate most jobs and much of humanity's relevance would rush to build that future." Never mind that Zuckerberg's Meta has cut 10% of its global workforce — about 8,000 jobs — as the company reorganizes to focus on AI. Zuckerberg's manifesto is the latest to land in our social media feeds in an effort to put a positive spin on AI. In 2024, ChatGPT-maker OpenAI boss Sam Altman released a manifesto called "The Intelligence Age", a sweeping expression of optimism about the tech's potential... That same year, in a manifesto titled "Machines of Loving Grace", Anthropic CEO Dario Amodei touted the potential of AI to transform everything from healthcare to politics. So what's going on with these tech executives' manifestos? Economics blogger Noah Smith suggested to the BBC "they all feel like it's such an important moment that it's incumbent upon them to do whatever they can to shape the direction that this technology is going." Although he does see some value in their engagement with important issues. "Should we open-source something that has the ability to kill humanity? If you don't take that seriously, you're just a fool." But Rob Lalka, a business professor at Tulane University, had a different explanation for the BBC: Lalka said the timing of Zuckerberg's manifesto coincides with rising anger over AI's impact on everything from jobs to the environment. And while tech journalists and academics might pore over them trying to glean nuggets of meaning, these executive manifestos are not necessarily landing with the general public. "They're trying to make the case that the positives will far outweigh some of those negatives that the public backlash is pointing out," he said. "But I think a lot of the reasons for optimism are still yet to be seen."

Read more of this story at Slashdot.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Disney D23 2026: Everything announced for Star Wars, Marvel, and more

1 Share
Ryan Gosling and Shawn Levy in front of a Star Wars Starfighter logo.
Shawn Levy, Ryan Gosling | Image: The Walt Disney Company/Image Group LA

The annual Disney fan event showed off the cast of Marvel’s X-Men movie, plus a new trailer for Avengers: Doomsday, and our first look at the VisionQuest TV show for Disney Plus. For Star Wars fans, there was a teaser trailer for season two of Ahsoka, plus a special look at Star Wars: Starfighter with an appearance from Ryan Gosling.

Other new announcements included a few updates about Pixar, The Simpsons, Bluey, and others you can find below.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

One-Shot UI Side Effects in BlocSignal: Snackbars, Dialogs, and Navigation Without State Pollution

1 Share

Every Flutter developer has run into the Sticky State Dilemma.

You build a login screen. When authentication fails, your state container emits an error. You catch it in your UI and show a SnackBar. Everything works—until the user rotates their phone, pulls down the notification shade, or types on the virtual keyboard.

Suddenly, the widget tree rebuilds. The state container is still holding AuthErrorState("Invalid password"). The UI listener fires again. And a duplicate snackbar appears out of nowhere.

In this article, we’ll explore why domain state machines struggle with transient UI events, how the classic BLoC community worked around this with package:bloc_presentation, and how BlocSignal lets you handle one-shot side effects cleanly with zero additional package dependencies.

1. The Root Problem: Persistent State vs. Ephemeral Actions

State management in Flutter is designed to model persistent truth over time:

  • Is the user logged in? AuthState.authenticated(user)
  • Is data loading? TodoState.loading
  • What is the cart total? $49.99

Persistent state answers: "What is the system's current condition?"

In contrast, UI presentation actions are ephemeral pulses:

  • Show a brief SnackBar toast.
  • Pop up an alert confirmation dialog.
  • Push a new route on the Navigator stack.
  • Vibrate the haptic motor.

These actions answer: "What just happened that requires a one-time reaction?"

 ┌────────────────────────────────────────────────────────┐
 │                   State vs. Effects                    │
 ├────────────────────────────┬───────────────────────────┤
 │ Persistent State           │ Ephemeral Side-Effect     │
 ├────────────────────────────┼───────────────────────────┤
 │ • Survived by UI rebuilds  │ • Consumed once & gone    │
 │ • Represented in signals   │ • Triggered by an event   │
 │ • Backed by equality diffs │ • Zero domain state footprint │
 └────────────────────────────┴───────────────────────────┘

2. The Legacy Workarounds (And Their Hidden Costs)

Historically in package:bloc and package:flutter_bloc, developers used one of three approaches:

Workaround A: The "Reset State" Ping-Pong

// Emitting a reset state immediately after error
emit(AuthFailure(error));
emit(AuthInitial()); // Extra emission, extra microtask, extra rebuild!

Downside: Causes two separate microtask queue ticks and multiple widget rebuild cycles just to reset a transient flag.

Workaround B: "Consumed" Wrapper Flags

class AuthState {
  final String? errorSnackbarMessage;
  final bool hasShownSnackbar; // Manual bookkeeping everywhere!
}

Downside: Clutters state classes with imperative UI tracking flags that violate domain purity.

Workaround C: package:bloc_presentation

LeanCode created package:bloc_presentation, adding a separate secondary StreamController.broadcast() to Blocs so developers could call emitPresentation(MyEvent()) independently of emit(state).

While bloc_presentation solved the problem well for classic BLoC, maintaining third-party wrapper packages in your monorepo introduces versioning churn, boilerplate, and dependency overhead.

3. The BlocSignal Advantage: 0ms Synchronous Guarantees

In BlocSignal, state propagation is synchronous.

Unlike classic BLoC which queues updates asynchronously on microtask-queue Streams, calling emit(newState) in BlocSignal updates the underlying reactive signal and settles dependencies immediately in the exact same frame.

Because state updates are synchronous, you often don't need any presentation streams at all!

Pattern 1: Direct Async UI Handlers (Recommended)

When an action is initiated by a user interaction (like tapping a button), the simplest and cleanest pattern is handling the reaction right in the button's onPressed callback:

ElevatedButton(
  onPressed: () async {
    final cubit = context.read<AuthCubit>();

    // 1. Await domain logic completion
    await cubit.signIn(emailController.text, passwordController.text);

    // 2. Safe async context guard
    if (!context.mounted) return;

    // 3. Inspect settled state synchronously with Dart pattern matching
    switch (cubit.stateValue) {
      case AuthSuccess(:final user):
        Navigator.of(context).pushReplacementNamed('/dashboard');
      case AuthFailure(:final error):
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text(error)),
        );
      case _:
        break;
    }
  },
  child: const Text('Log In'),
)

Why this works so well in BlocSignal:

  • Zero Race Conditions: The moment cubit.signIn(...) finishes, cubit.stateValue is 100% up to date.
  • Zero Duplicate Triggers: Screen rotations or unrelated rebuilds will never re-execute the button handler.
  • Zero Extra Code: No special listeners, no extra streams, no consumable wrapper classes.

4. The Zero-Dependency PresentationMixin Recipe

What if your domain state machine triggers side-effects autonomously (for example, an incoming WebSocket disconnects, a background sync finishes, or you are migrating an existing codebase from bloc_presentation)?

You can drop in a 100% compatible presentation architecture in ~25 lines of pure Dart without adding any 3rd-party dependencies.

Step 1: The Mixin (BlocSignalPresentationMixin)

import 'dart:async';
import 'package:bloc_signals/bloc_signals.dart';

/// Mixin that adds one-shot presentation event broadcasting to any [BlocSignalBase].
mixin BlocSignalPresentationMixin<Event, State> on BlocSignalBase<State> {
  final _presentationController = StreamController<Event>.broadcast();

  /// Stream of one-shot presentation events.
  Stream<Event> get presentationStream => _presentationController.stream;

  /// Dispatches a one-shot presentation event to active UI listeners.
  void emitPresentation(Event event) {
    if (!isClosed) {
      _presentationController.add(event);
    }
  }

  @override
  Future<void> close() {
    _presentationController.close();
    return super.close();
  }
}

Step 2: The Flutter Listener (BlocSignalPresentationListener)

import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:bloc_signals_flutter/bloc_signals_flutter.dart';

/// Listens to one-shot presentation events from a [BlocSignalBase] with [BlocSignalPresentationMixin].
class BlocSignalPresentationListener<
        B extends BlocSignalPresentationMixin<Event, dynamic>, Event>
    extends StatefulWidget {
  const BlocSignalPresentationListener({
    required this.listener,
    this.bloc,
    this.child,
    super.key,
  });

  final B? bloc;
  final void Function(BuildContext context, Event event) listener;
  final Widget? child;

  @override
  State<BlocSignalPresentationListener<B, Event>> createState() =>
      _BlocSignalPresentationListenerState<B, Event>();
}

class _BlocSignalPresentationListenerState<
        B extends BlocSignalPresentationMixin<Event, dynamic>, Event>
    extends State<BlocSignalPresentationListener<B, Event>> {
  StreamSubscription<Event>? _subscription;
  B? _resolvedBloc;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final bloc = widget.bloc ?? context.read<B>();
    if (_resolvedBloc != bloc) {
      _unsubscribe();
      _resolvedBloc = bloc;
      _subscribe();
    }
  }

  void _subscribe() {
    _subscription = _resolvedBloc?.presentationStream.listen((event) {
      if (mounted) widget.listener(context, event);
    });
  }

  void _unsubscribe() {
    _subscription?.cancel();
    _subscription = null;
  }

  @override
  void dispose() {
    _unsubscribe();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => widget.child ?? const SizedBox.shrink();
}

5. Putting It Together: A Real-World Example

Let's see how clean our Cubit and UI look when composed together:

1. Events & Cubit Definition

import 'package:bloc_signals/bloc_signals.dart';

// 1. Define one-shot presentation events as a sealed hierarchy
sealed class CheckoutPresentationEvent {}

class ShowErrorToast extends CheckoutPresentationEvent {
  ShowErrorToast(this.message);
  final String message;
}

class LaunchPaymentGateway extends CheckoutPresentationEvent {
  LaunchPaymentGateway(this.invoiceUrl);
  final String invoiceUrl;
}

// 2. Attach the mixin to your Cubit or Bloc
class CheckoutCubit extends CubitSignal<CheckoutState>
    with BlocSignalPresentationMixin<CheckoutPresentationEvent, CheckoutState> {
  CheckoutCubit() : super(initialState: CheckoutInitial());

  Future<void> processPayment() async {
    emit(CheckoutProcessing());
    try {
      final invoice = await paymentApi.createInvoice();
      emit(CheckoutSuccess());

      // Emit one-shot navigation/payment launch event
      emitPresentation(LaunchPaymentGateway(invoice.url));
    } catch (e) {
      emit(CheckoutFailure(e.toString()));

      // Emit transient error toast event
      emitPresentation(ShowErrorToast("Payment failed: ${e.toString()}"));
    }
  }
}

2. The Flutter UI

class CheckoutView extends StatelessWidget {
  const CheckoutView({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocSignalPresentationListener<CheckoutCubit, CheckoutPresentationEvent>(
      listener: (context, event) {
        switch (event) {
          case ShowErrorToast(:final message):
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(message),
                backgroundColor: Colors.redAccent,
              ),
            );
          case LaunchPaymentGateway(:final invoiceUrl):
            launchUrl(Uri.parse(invoiceUrl));
        }
      },
      child: Scaffold(
        appBar: AppBar(title: const Text('Checkout')),
        body: const CheckoutBody(),
      ),
    );
  }
}

6. Migration Comparison Matrix

Feature Legacy bloc_presentation BlocSignal Presentation Recipe
External Dependencies package:bloc_presentation + nested 0 external dependencies
Architecture Stream-based side channel Stream-based side channel
Emission Syntax emitPresentation(event) emitPresentation(event)
Listener Widget BlocPresentationListener BlocSignalPresentationListener
Automatic Cleanup Manual stream closing Managed in close() lifecycle
State Reactivity Microtask Streams Synchronous Signals (0ms)

Summary

Handling one-shot side-effects shouldn't require complex state hacks or heavy external packages:

  1. For user interactions: Use Direct Async UI Handlers (await cubit.action())—BlocSignal's synchronous emissions make this glitch-free and safe.
  2. For asynchronous domain broadcasts: Use the 25-line BlocSignalPresentationMixin recipe for 100% bloc_presentation parity with zero dependencies.
  3. Keep domain state clean: Keep persistent data in stateValue and ephemeral UI triggers in presentation streams.

Resources & Links

Read the whole story
alvinashcraft
3 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

I’m Writing a Book on WebAssembly and Spin

1 Share

Hey friends 👋🏼,

If you’ve been following my activities over the recent years, you know I can’t stop talking about the third wave of cloud computing. Server-side WebAssembly is completely changing the game for cold-start latency and container bloat.

Today, I’m thrilled to announce I’m turning those talks and architectural patterns into a practical, hands-on guide:

Building Serverless Applications With WebAssembly & Spin

Sign uo and Stay in the Loop

Instead of theoretical fluff, I structure the book in a way that readers will build a complete, multi-component serverless application from the ground up using Rust and Spin.

Read the whole story
alvinashcraft
3 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Uno Apps Inside of Uno Apps

1 Share

I posted a fun little experiment the other day and I wanted to follow it up with the real story of how it works. Here’s the tweet:

Running your @UnoPlatform apps inside of your @UnoPlatform apps ;)

Inspired by the plumbing of Uno Platform Studio, I thought it’d be fun to take advantage of AssemblyLoadContext to load each Uno Themes sample app inside of a new SUPER THEMES APP. Works surprisingly well!

And here’s the thing actually running. One app, and I’m picking which whole other app renders inside it, live:

What Even Is This

The Uno.Themes repo contains three sample apps, one per design system: Material, Simple, and Cupertino (out of support). I wanted a single app where I could tap a button and load any of them, then unload it and load the next one. The catch is that these aren’t little user controls I’m swapping in. Each one is a complete, independent Uno application, with its own resources, its own theme library, its own everything. What you’re watching in that video is one Uno app hosting another entire Uno app, swapping between three of them, with a clean* teardown in between.

But Like, Why?

Is this just some flashy demoware?

No! I have reasons; and they are threefold:

  1. This is the underlying plumbing the powers Uno Platform Studio, more on that later

  2. Today, testing each Themes app means launching a different sample head for each one. It means packaging each one separately. It means deploying to three separate slots in the dev environment via the CI. It means a larger, more complex setup locally and on the CI. It’s also a way to test the themes in a single staging slot for every pull request, instead of three separate ones.

  3. It’s also a single entry point for automated runtime tests that need to run against all three themes. Imagine having a single “runner” app that is capable of being provided a set of automated runtime test cases, and then running them against the live app to be tested. That’s the payoff.

The wrapper app hosting the Material, Cupertino, and Simple theme samples one at a time, each showing an 'is running' status

A Quick Word on AssemblyLoadContext

The piece of .NET that makes this possible is AssemblyLoadContext, or ALC. If you’ve never had a reason to reach for it, here’s the two-minute version.

Normally every assembly your app loads goes into one big shared bucket, the default load context. ALC lets you create additional, isolated buckets. Two different contexts can each load an assembly with the same name, even different versions of it, and the runtime treats them as genuinely separate. Worth being precise about “isolated” though, because it isn’t a sandbox. There’s no binary isolation between contexts, they’re only isolated by not finding each other by name.

And things get weird when you start sharing types across contexts.

Standing on Uno Studio’s Shoulders

I did not invent the hard part here. Uno Platform Studio already does exactly this in production: it loads your app into a fresh collectible AssemblyLoadContext and runs it inside the Studio process itself. Hot Design then rides along inside that same context, which is how it can turn your live, running app into a designer. That plumbing is exactly what I needed: loading and running a whole app inside another app’s world. The Uno runtime exposes the pieces that make it work as public API, and I just wired them together for a much simpler purpose.

There are really only three moving parts:

  • AlcContentHost, a ContentControl you drop into your visual tree to reserve a spot for the guest.
  • WindowHelper.ContentHostOverride, which you point at that host so a guest’s window content gets redirected into it instead of trying to open its own native window.
  • A second UnoPlatformHostBuilder, which you build around the guest’s Application and run.

The Host Side

On the parent app’s main page, I create the AlcContentHost once and register it as the override for the whole app’s lifetime:

1
2
3
4
5
_contentHost = new AlcContentHost { HorizontalAlignment = HorizontalAlignment.Stretch };
GuestRegion.Child = _contentHost;

// Redirect any hosted guest's window into our region.
WindowHelper.ContentHostOverride = _contentHost;

Source: ThemesSampleApp/MainPage.xaml.cs

When you pick a theme, the loader creates a fresh collectible ALC, loads the guest’s assemblies into it, and starts the guest with its own host builder. The important subtlety is what gets shared versus isolated. The Uno framework assemblies (Uno.UI and friends) are shared from the default context, because if the host and the guest each loaded their own Uno.UI, their types would not be the same types and nothing would line up. The guest’s own code and its theme library, on the other hand, stay fully isolated inside the collectible context. That whole shared-versus-isolated policy now lives in a single data file that both the loader and the build step read, so the runtime and the packaging can never quietly drift apart.

Starting the guest looks roughly like this. Note that it never runs the guest’s Program.Main, it builds a brand new host around the guest’s App:

1
2
3
4
5
6
7
var builder = UnoPlatformHostBuilder.Create().App(capturingFactory);
#if __WASM__
    builder = builder.UseWebAssembly();
#else
    builder = builder.UseX11().UseLinuxFrameBuffer().UseMacOS().UseWin32();
#endif
var host = builder.Build();

Source: GuestAppLoader.Desktop.cs and GuestAppLoader.Wasm.cs — split per platform in the repo rather than #if‘d in one file

From there the guest constructs its App, sets up its window, and Uno quietly redirects that window’s content into the AlcContentHost. The guest thinks it’s a normal top-level app. It has no idea it’s a guest. There’s an important subtlety here about how the guest app’s content is plumbed through. We aren’t dealing nesting Windows or multiple App instances or multiple independent visual trees. When we set the WindowHelper.ContentHostOverride to _contentHost, we are telling the Uno runtime that any Window created in the guest context should have its content redirected to the AlcContentHost. This allows the guest app to behave as if it has its own window, while actually rendering inside the host’s visual tree. So, one visual tree for both apps.

And yes, it makes resource resolution a bitch sometimes.

Two Tiny Changes to Each Guest

The coolest part is how little the sample apps had to change to become hostable. Exactly two things, and both are one-liners.

First, one property in the csproj so the XAML generator knows this app might be hosted and scopes its resource dictionaries to the right load context. Basically, this is how we can ensure that the guest’s static resources don’t leak into the host’s world, and vice versa. Well, actually, it’s how the XAML generator knows to generate code that allows us to know which resources belong to which context. The Uno XAML generator has to be aware of the hosting scenario so it can generate code that respects the boundaries of the load contexts.

Add this to the guest’s csproj:

1
<UnoEnableAlcAppSupport>true</UnoEnableAlcAppSupport>

Source: MaterialSampleApp.csproj — identical line in the Cupertino and Simple heads

Second, and this one is a genuine gotcha, the sample apps used to grab their window like this:

1
MainWindow = Microsoft.UI.Xaml.Window.Current;

Window.Current is a process-wide static living in the shared Uno.UI. When the app runs hosted, that static is the wrapper’s window, so the guest would reach up and grab the host’s window and promptly try to close it. The fix is to just make a new one:

1
MainWindow = new Microsoft.UI.Xaml.Window();

Source: MaterialSampleApp/App.xaml.cs — identical line in the Cupertino and Simple heads

That’s still correct when the app runs standalone, because the first new Window() maps to the main window anyway. So the sample heads stay completely standalone. They gained the ability to be hosted without giving up the ability to run on their own.

Guests Overstaying Their Welcome

Just the thought of loading, unloading, switching, and reloading assemblies over and over again during the app’s lifetime is causing my RAM usage to skyrocket. It sounds like a recipe for leaks, and it is. The collectible ALC is supposed to reclaim its memory when nothing outside it points at anything inside it, but Uno’s shared assemblies are non-collectible code that can hold references into the guest. If a static in Uno.UI still points at a guest object after teardown, the whole context stays alive.

The direction matters here: Guest → host references are fine. Host → guest is what kills you. A non-collectible root reaching into collectible memory. And it’s not always as straightforward as it sound. In fact, as a result of this app and blog, we identified a few leaks that need to be cleaned up! More on that in a bit.

This is why we now have a hosting smoke test wired into CI: every build loads all three guests, unloads them, and asserts that each load context was actually reclaimed. If a future change starts leaking, the build fails instead of the leak sneaking through.

The test itself is boring in the best way. Launch the wrapper with --smoke on desktop or ?smoke in the browser and it drives itself: load each guest in turn, unload the last one, and check reclamation after every step. It’s not perfect, I know. Technically, we should be be loading and unloading over and over again and maintain a count of maintained references that should be kept underneath a realistic threshold, but this is a smoke test, not a stress test.

The Eviction

The eviction is the part that actually tears down the guest. It calls ExitAlcApplication() to clean up the guest’s static caches, then it sweeps a few Uno internals to make sure nothing is still pointing at the collectible context. Finally, it drops its reference to the ALC and forces a GC collection, then probes to see if the context was reclaimed.

It starts politely, by asking the guest to exit itself. Application.Exit() is what internally triggers ExitAlcApplication(), which sweeps the per-ALC static caches:

1
2
3
4
if (session.GuestApp is { } guestApp)
{
    await RunOnUIThreadAsync(guestApp.Exit).ConfigureAwait(false);
}

Source: GuestAppLoader.TeardownUnguardedAsync

Then every reference the session holds gets dropped before the unload, because anything still pointing into the guest at this moment pins the context. The weak reference is deliberately the only thing left holding the ALC:

1
2
3
4
5
6
7
var alc = session.Alc;
session.GuestApp = null;
session.ExecutionTask = null;
session.ExecutionThread = null;

await Task.Run(alc.Dispose).ConfigureAwait(false);
_lastUnloadedAlc = new WeakReference<GuestAssemblyLoadContext>(alc);

Source: GuestAppLoader.TeardownUnguardedAsync

Ordering is the whole trick in the next bit. Guest DependencyObject finalizers run during the unload and can re-populate the shared property-system caches after ExitAlcApplication already swept them, so the sweep has to come after the finalizers drain, not before:

1
2
3
4
5
GC.Collect();
await DrainFinalizersAsync().ConfigureAwait(false);
await RunOnUIThreadAsync(SweepNonDefaultAlcCaches).ConfigureAwait(false);

GC.Collect();

Source: GuestAppLoader.TeardownUnguardedAsync — the sweep call is wrapped in a warning check in the repo

And the verdict is just a weak-reference probe. If the target is still reachable after all that, something in the host is still rooting the guest:

1
2
3
4
5
6
7
8
9
if (weakAlc.TryGetTarget(out var previous))
{
    LastUnloadedAlcCollected = false;
    _logger.LogWarning("Previous guest ALC {Name} is still alive after unload + GC.", previous.Name);
}
else
{
    LastUnloadedAlcCollected = true;
}

Source: GuestAppLoader.ReportPreviousAlcCollectionState

Sweeping Up

That SweepNonDefaultAlcCaches call is the honest ugly part. It’s three reflection-based pokes at Uno internals, deliberately parked in one file so they’re easy to delete later, and every one of them degrades to a logged warning rather than an exception if a future Uno rename moves the target.

I won’t go into each sweep, but we can focus on what I think is the most interesting one. This is the one that that illustrates the hidden complexity of the Guest → host references are fine. Host → guest is what kills you rule. The SystemNavigationManager.BackRequested event is a process-wide static in the shared Uno.UI, and the guest’s Shell subscribes to it. At face-value, this may sound like a guest -> host reference. But this is one of those pesky cases where the guest’s subscription roots the guest itself. The event is a multicast delegate, and the invocation list holds strong references to each subscriber.

Nothing unsubscribes it on teardown, so the stale handler roots the guest’s entire visual tree. The fix is to walk the invocation list and drop anything whose origin lives in a collectible context:

Remaining Sweeps

Why Bother

Beyond it just being cool, there’s a real payoff. The Uno.Themes repo deploys a staging site for every pull request, and it used to only cover the Simple theme. This wrapper now lets one deployment host all three theme samples behind a picker, so every PR gets a single staging site that covers Material, Cupertino, and Simple at once. The fun demo turned into an actual improvement to how we test the themes.

There’s also something I like about pulling back the curtain. The ALC hosting that powers Uno Platform Studio can feel like magic when it’s buried inside a product. Wiring it up myself, and hitting all the sharp edges, made it a lot less magical and a lot more approachable. If you want to see the whole thing, warts and workarounds included, all of the code is in the pull request.

I should also mention I built this alongside an agent, using Claude Code, which fits right in with the agentic development thread I’ve been on lately. Chasing down a trimmer stripping type-forwarders is exactly the kind of deep, weird problem where having a tireless pair helps.

Conclusion

So there it is. Uno apps running inside Uno apps, one collectible load context at a time, built on the same runtime plumbing that Uno Platform Studio uses in production. It started as a “wouldn’t it be funny if” and turned into both a genuine testing improvement and the most I’ve learned about AssemblyLoadContext in one sitting.

If you go try something like this yourself, do it on a 6.7 build (may still be prerelease -dev builds at the time of this post) and expect to get friendly with load contexts. And if you build something sillier than a SUPER THEMES APP, please come show me in the Uno Discord ;).

Catch you in the next one :wave:

* We are still hunting down some leaks, we’ve made good progress but memory management is hard ok? Give us a break.



Read the whole story
alvinashcraft
3 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Enterprise NoSQL Modernization: What Migration Planning Gets Wrong

1 Share

A data migration strategy for NoSQL modernization fails when it treats database replacement as a data transfer problem. It’s actually a program execution problem.

Many enterprise modernization initiatives begin with months of evaluating database platforms, comparing features, benchmarking performance, and selecting a target architecture. Yet once the technology decision is made, the most difficult work is still ahead. Teams discover that application dependencies are more extensive than expected, data models require significant redesign, rollout timelines become unrealistic, and rollback procedures haven’t been fully defined. The result is that database modernization programs stall not because the chosen platform is incapable, but because the effort required to execute the migration was underestimated.

Successful modernization depends on building a realistic execution strategy that aligns architecture, applications, operations, and business priorities before migration begins. Organizations that invest heavily in technology evaluation while treating planning as a downstream activity frequently encounter schedule overruns, unexpected costs, and prolonged periods of operating parallel systems.

This article examines six of the most common migration planning gaps that emerge after kickoff and explores how to address them before they become delivery risks. We’ll cover why technology selection is only the starting point, how data model translation introduces hidden complexity, why application refactoring must be scoped early, how phased execution reduces operational risk, why rollback planning should be part of every data modernization strategy, and how to build a compelling business case that keeps modernization efforts funded and aligned through completion.

Why NoSQL Modernization Programs Stall After Technology Selection

Technology selection is often an easier part of a data modernization initiative. The new platform is approved, budgets are allocated, vendors are selected, and project teams are ready to begin. What frequently receives less attention is the execution plan needed to deliver the migration successfully. As a result, implementation becomes an exercise in solving unexpected problems rather than following a well-defined data migration strategy.

The first 90 days are where planning gaps typically surface, and three issues account for many stalled modernization efforts:

Data model translation is treated as a database task instead of an architectural design exercise. Teams focus on moving data without fully accounting for changes to document structures, indexing strategies, and application access patterns.

Application refactoring is discovered during execution rather than planned up front. Query logic, APIs, and data access layers often require more changes than initially estimated, expanding project scope after work has already begun.

Rollback planning is undefined. Without a clear fallback strategy, deployments become high-risk, all-or-nothing events that delay releases and increase operational risk.

Most content on NoSQL modernization focuses on evaluating database technologies or explaining their benefits. Far less attention is given to the NoSQL migration planning required to execute a successful database modernization program, but that’s where many projects ultimately succeed or fail.

The Data Model Translation Problem Most Architects Underestimate

A successful data migration strategy involves far more than moving data from one platform to another. It also requires redesigning how data is modeled for a JSON document database, and those decisions should be made by architects – not just by database administrators.

Three design choices have the greatest impact on application performance and maintainability:

  • Embedded vs. referenced documents – Embedding related data can reduce joins and improve read performance, but it can also make updates more complex. Referencing preserves a more relational structure but often misses the performance advantages of the document model.
  • Denormalization – Document databases intentionally duplicate some data to optimize common queries. The challenge is determining how much duplication improves performance without creating unnecessary consistency or maintenance overhead.
  • Index strategy – A JSON document database indexes data differently than a relational database. Query patterns should be understood and mapped before the data model is finalized so indexes support the application’s most important workloads from day one.

These architectural decisions influence performance, scalability, and development effort long after the migration is complete. Rather than treating schema conversion as a one-time mapping exercise, make data modeling a core part of your migration planning. For guidance on designing document-oriented schemas, see Couchbase’s flexible JSON data modeling guide.

Application Modernization Strategy: Scoping Refactoring Before Migration Starts

Many database migration strategy plans focus on moving data but underestimate the application changes required to support the new platform. Identifying these changes early is a critical part of any application modernization strategy.

Three areas of application modernization strategy deserve attention before migration begins:

  • Query language translation – Moving from SQL to SQL++ reduces the learning curve because the syntax is familiar, but existing queries will still need review. Aggregations, joins, subqueries, and database-specific functions often require rewriting or optimization.
  • Connection and driver changes – Applications may need updates to database drivers, connection management, retry policies, and error handling. These infrastructure changes can affect far more code than expected.
  • Schema assumptions – Applications built around rigid relational schemas often assume fixed table structures and predictable relationships. Those assumptions should be identified and removed before adopting a more flexible document model.

A practical way to estimate the true scope is to perform an application refactoring audit on one representative application before finalizing migration planning. The findings typically reveal the effort required across the broader application portfolio, resulting in a more realistic database migration strategy and fewer surprises during execution.

If your team is looking for migration support, Couchbase Professional Services can provide expert guidance for assessment and migration, plus hands-on support and training that’s all tailored to your needs.

Phased Execution for Enterprise Database Modernization

One of the biggest mistakes in migration planning is attempting to migrate every workload at once. A single cutover may seem faster, but it maximizes risk while giving teams little opportunity to learn and adapt. A phased approach does the opposite, allowing organizations to refine their process before migrating business-critical systems.

A typical database modernization program follows three phases:

  • Phase 1: Pilot workload – Start with a lower-risk application that represents your core data model and query patterns. This will give architects and developers an opportunity to validate assumptions and gain operational experience before production-scale deployment.
  • Phase 2: Core migration – Apply lessons from the pilot to migrate higher-volume or mission-critical workloads. Each migration should have clearly defined cutover windows, success criteria, and validation checkpoints.
  • Phase 3: Legacy decommission – Complete the legacy database migration only after the new environment has met performance, stability, and business requirements during a defined validation period. Retiring legacy infrastructure too early can make recovery significantly more difficult if issues emerge.

Phased execution reduces operational risk while improving delivery confidence. More importantly, it turns each migration into a learning opportunity that strengthens the overall application modernization strategy and data modernization program rather than treating the first production deployment as the final exam.

If you’re ready to get a feel for your migration process, we make it easy to start a pilot workload on Couchbase Capella, our fully managed DBaaS.

Rollback Planning: The Gap in Most Database Migration Strategies

Most teams treat migration as a one-way process, and once the cutover begins, there’s no going back. In reality, a sound database migration strategy assumes that rollback may be necessary and plans for it from the start.

During the cutover and validation window, both the legacy and target databases should remain synchronized so changes can flow in either direction if required. This bidirectional synchronization gives teams time to validate application behavior, query performance, and data integrity before committing to the new platform.

Before decommissioning the source system, establish clear data consistency checkpoints to verify that records, transactions, and application results are consistent across both environments. Equally important is application routing control, which allows traffic to be redirected back to the legacy database via configuration or infrastructure changes rather than an emergency code deployment.

Without rollback planning, every migration becomes a bet-the-business event. With it, cutover becomes a controlled decision point within a resilient data migration strategy. Rollback planning reduces risk while giving stakeholders confidence that issues can be resolved without disrupting production.

Building the Internal Business Case for Legacy Database Migration

Executive approval may launch a legacy database migration, but sustained sponsorship is what keeps it on track. As timelines shift and priorities compete, architects need to continually connect technical progress to measurable business outcomes.

An effective business case should reinforce three areas:

  • Risk of inaction – Quantify the business impact of delaying modernization, including performance limitations, rising maintenance costs, and difficulty hiring and retaining developers for aging technology stacks.
  • Development velocity – Show how a modern document database enables faster feature delivery through schema flexibility, simplified application development, and shorter deployment cycles.

At each project milestone, your architects should translate technical decisions into business terms that executives understand. Focus on lower operating costs, reduced risk, and faster delivery. Maintaining that connection throughout execution can make the difference between successfully completing your data modernization project and losing momentum.

To build a strong business case, you can use our benchmark reports, comparison table, and other resources to compare NoSQL database options.

FAQs on Data Migration Strategy

What is a data migration strategy for NoSQL modernization?

A data migration strategy is a program-level plan for executing a successful modernization effort. In addition to moving data, it should address data model translation, application refactoring, phased workload execution, rollback planning, and stakeholder alignment to reduce delivery risk.

What is the biggest risk in a database modernization program?

The biggest risk is underestimating application changes. Many organizations carefully plan data migration but fail to fully scope query rewrites, connection management updates, and schema assumptions embedded in application code. These issues often become the primary source of delays.

How do you phase an enterprise NoSQL migration?

Begin your NoSQL migration with a lower-risk pilot that reflects your core data model and query patterns. Apply the lessons learned before migrating higher-volume or business-critical workloads. Decommission the legacy database only after the new environment has completed a successful validation period.

Is MongoDB migration the same as other NoSQL migrations?

No. While a MongoDB to Couchbase migration moves data between two JSON document databases, it still requires planning for query language differences, index optimization, driver updates, and application behavior. Sharing a JSON document model simplifies some aspects of migration, but it doesn’t eliminate the need for a comprehensive migration plan. For a closer look at their similarities and differences, see our collection of resources for comparing Couchbase vs. MongoDB.

The post Enterprise NoSQL Modernization: What Migration Planning Gets Wrong appeared first on The Couchbase Blog.

Read the whole story
alvinashcraft
4 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories