Brett Owers
← All Projects

Location BLoC Example

Archived

February 1, 2020

A Flutter app attempting to handle location-based logic using BLoC on the client — logic that should have lived on the server. A hard lesson in where state management belongs, and a tour through the major state management patterns in modern app development.

Purpose

Tried to build location-based features using BLoC for state management entirely on the client side. The app worked, but the architecture was wrong — complex filtering, matching, and geospatial queries were being computed on the phone instead of on a server where they belonged. The mistake was instructive.

Stack

FlutterDartBLoCGeolocationState Management

What I Learned

  • The first question of state management is not "which pattern?" — it is "where does this state live?" Client state (UI visibility, form inputs, animation progress) belongs on the client. Server state (user data, business logic results, computed aggregations) belongs on the server. This project tried to run server-grade geospatial computations inside a BLoC on the phone. It was slow, battery-draining, and architecturally wrong. The BLoC was not the problem. The location of the logic was.
  • BLoC (Business Logic Component) separates concerns through a stream-based pattern: the UI dispatches Events, the BLoC processes them and emits States, the UI rebuilds reactively. Events in, states out, no direct mutation. It is Redux-flavored but stream-native. Strengths: testable, predictable, enforces separation. Weaknesses: verbose, lots of boilerplate, overkill for simple state.
  • Provider is Flutter's simplest state management approach — it uses InheritedWidget under the hood to make objects available down the widget tree. ChangeNotifier + Provider gives you a lightweight observable pattern: mutate state, call notifyListeners(), widgets rebuild. Best for small-to-medium apps where BLoC is too heavy.
  • Riverpod is Provider's successor — it fixes Provider's dependency on the widget tree by making providers global and compile-time safe. No BuildContext required to read state. Supports async, family providers (parameterized), and auto-dispose. It is where the Flutter ecosystem is converging for new projects.
  • Redux (in any framework) is a single global store with reducers that produce new state from actions. Predictable and debuggable (time-travel debugging, action logging) but extremely verbose. React adopted and then largely moved away from it in favor of hooks and context. Flutter's redux package exists but most teams prefer BLoC or Riverpod.
  • Zustand, Jotai, Recoil (React ecosystem) and GetX, MobX (Flutter ecosystem) represent the "minimal boilerplate" school — atomic state, direct mutation, less ceremony. They trade the predictability guarantees of BLoC/Redux for developer speed. The right choice depends on team size, app complexity, and how much you trust future developers (including yourself) to maintain discipline without guardrails.
  • The signals pattern (Solid.js, Angular Signals, Preact Signals, and increasingly Flutter) is the newest convergence: fine-grained reactive primitives that automatically track dependencies and update only the UI that depends on changed values. No explicit subscriptions, no manual rebuilds, no unnecessary re-renders. This is likely where all frameworks are headed.

Key Insights

  • State management debates (BLoC vs Provider vs Riverpod vs Redux) miss the more important question: what is client state and what is server state? A geospatial matching query does not become client state just because you wrote it in a BLoC. It is still server logic — you just put it in the wrong place. The pattern you choose matters less than the boundary you draw between client and server responsibilities.
  • The heuristic: if the logic requires data the client does not have, it belongs on the server. If the logic produces results that multiple clients need to agree on, it belongs on the server. If the logic is computationally expensive and the client is a phone with a battery, it belongs on the server. Client state management is for UI orchestration — what is visible, what is loading, what the user has typed. Business logic belongs behind an API.
  • Every state management pattern is a different answer to the same question: "when data changes, what else needs to update?" BLoC answers with streams. Provider answers with listeners. Redux answers with a global store and selectors. Signals answer with automatic dependency tracking. Understanding the question is more portable than mastering any single answer.
  • This project was a rite of passage — every developer has at least one project where they put the wrong logic on the wrong side of the client/server boundary. The lesson sticks precisely because it hurts: the app was slow, the code was complex, and the fix was to delete most of it and make an API call instead.
#Flutter#Dart#BLoC#state-management#Provider#Riverpod#Redux#signals#client-server#architecture#geolocation#patterns

This post was composed through a conversation between Brett Owers and Claude Code (Anthropic). The content reflects Brett's recollection of each project and the lessons drawn from it. Some details may be approximate or omitted — the purpose is to paint an honest picture of a software engineer's development over time, not to serve as a precise historical record.