Build Better Mobile Line-of-Business Apps with Reactive Properties & JSON Patch

What is ChainReact.NET?

ChainReact.NET is a client-server framework I’ve developed while, and in support of, developing a multilingual Point-of-Sale app (see the full backstory). The framework provides a faster and easier way to develop better mobile line-of-business apps, for any industry, that come alive based on user interactions on the current and other clients. Apps are faster and easier to build in that most of the client-side and server-side code you write is business logic instead of infrastructure. They’re better apps in that the UI is very responsive to user interactions, and quickly reflects data changes made on the current and other clients.

Once you learn the high-level concepts underlying my framework, and the techniques to take advantage of them, expressing business logic and implementing features becomes frictionless. You can do so more quickly and easily than before by benefiting from interconnected properties that always have up-to-date values. Changes ripple through the domain model on the current and other clients. The complicated infrastructure stuff is handled for you behind the scenes, so you can comfortably remain oblivious to its inner workings. This lets you stay focused on fulfilling actual business needs, while relying on the framework to breathe life into your logic and features across clients.

The framework does not take an “everything but the kitchen sink” approach. It’s designed to be one module, albiet a central one, for you to weave into the tapestry that is your app. It’s opinionated, but only to the extent necessary to fulfill its well-defined purpose. It augments your power as a coder; it doesn’t diminish it.

ChainReact.NET Libraries

  • ChainReact.NET consists of separate libraries.
  • Core
    • Reactive properties
  • Client-side
    • Includes other client-side functionality that benefits from reactive properties (view models, validation, etc.)
  • Server-side
    • Centers around JSON Patch
    • Includes database-specific patch contexts
    • Helps your build your PatchHub class
  • The libraries complement each other.
    • Together they interconnect properties across clients.
    • Changes ripple through the domain model on the current and other clients.

Persistent vs. Calculated Properties

  • A domain object has both persistent and calculated properties
  • A persistent property’s original value comes from the server, and its changed value is saved back to the server.
  • A domain object’s calculated properties are:
    • excluded from data transfer
    • used by multiple view-models
  • View-models also have their own calculated properties.
  • Calculated properties are reactive; persistent properties usually aren’t.

What’s a reactive property?

The Updater class enlivens domain and view models with functional reactive properties.

Reactive Updater as used in my app’s Bill domain object
  • A reactive property’s value is coded as a functional expression that references other properties.
  • If the value of a property referenced in a reactive property’s value expression changes, the reactive property is immediately updated.
  • When a change is made locally or received from across the network, related changes immediately ripple throughout the domain model and UI.

MVVM: View-Model Support

The client-side library leverages Updater to provide view-model classes and base classes that you can use in your apps.

Command view-model as used in my app’s BillPM view-model
  • The Command view-model class has a CanExecute reactive property.
  • The abstract TrackingScreen view-model class has a Sources reactive property.
  • Other provided view-model classes benefit from reactive properties in various ways.
  • Your view-models can and should have their own reactive properties.

Client-Server Architecture

  • 3-tiers: mobile app, web server, and database
  • .NET clients have a rich domain model.
  • Client joins the network, and it gets its initial data.
  • Each app/user has a different perspective of what’s in the database. It’s typically a much smaller subset than everything there.
  • The client thereafter syncs domain object change deltas to the database, via my server-side library, and to other clients.

Synchronization Made Easy

The framework syncs domain object deltas from a client to the server and other clients.

SetTrackedProperty as used in my app’s Bill domain object
  • Coding domain objects that accumulate deltas is easy using the Entity base class.
  • The TrackingScreen view-model base class calls Entity’s StartTracking and Commit methods when the user navigates to/from a screen.

A Delta’s Journey

  • Entity.StartTracking begins tracking changes.
  • Entity.Commit packages changes as a delta for sending server-side.
  • The server applies changes to:
    • the database by translating to database commands (currently MongoDB; extensible to others)
    • other clients by broadcasting via SignalR Core (Web Sockets)
  • Each client applies the changes to their in-memory copy of the data.
  • The original server call returns a delta with database generated object IDs to the client that originated the changes.

What’s a patch document? (RFC 6902)

    { “op”: “add”, “path”: “/a/b/c”, “value”: [ “foo”, “bar” ] },
    { “op”: “remove”, “path”: “/a/b/c” },
    { “op”: “replace”, “path”: “/a/b/c”, “value”: 42 },

  • It’s a list of operations that collectively describe a delta.
  • An operation can add, replace, or remove a value.
  • An operation has a path and a value.
  • I based my “Entity JSON Patch” format on JSON Patch.
  • An Entity JSON Patch document fits inside the structure of a JSON Patch document.

What’s special about Entity JSON Patch?

Patch operation on the Bill domain object
  • Specialized to operate on object models instead of plain JSON data
  • add ops are only used on arrays, and replace ops only on single-valued properties. RFC 6902 is less constrained.
  • Array indices are redefined as object IDs.
  • Special values reference new or existing objects.
  • For more information, see my Github issue.

What’s left to do?

  • Support a patch op that moves an object from one list to another.
  • Have the server add previously-filtered-out data to clients’ memories as its Query Filters are affected by value changes.
  • Have the server use Query Filters to produce a client’s initial data. Currently, I’m writing app-specific code.
  • Evolve Entity.Commit into offline sync functionality.
  • Write an Entity JSON Patch RFC!
  • Code server-side patch context subclasses for EF Core and other document databases. So far, only the MongoDB one is done.