ribs 0.1.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 52

flutter_ribs #

A port of uber/ribs, a novel approach to app architecture which places business logic, deep linking, a/b testing, and codebase stability as first class citizens.

Introduction #

So, a couple years ago, Uber decided to do a major refactor of their mobile apps, and decided to structure their state tree based on business logic instead of view logic. This created a novel approach to mobile app architecture that I believe is worth studying, which is why I ported it to Dart as a Flutter package.

At first the approach seems odd, if we build our app as a view logic tree, why would we instead try to structure it as a business logic tree? And what the heck do they mean by business logic? As a term, it can be quite nebulous.

Business Logic Tree #

Business logic tree

The business logic tree is made up of customer states. Are they logged in, or not? Based on that state, what can they do, and how do they transition towards the goal of being a paying customer?

Each cell above is a rib, and not all of them have a view.

At first glance, this may appear to be a view logic tree, and my suspicion is that well architected apps tend to have a view logic tree that closely matches the business logic tree. But structuring the tree with business logic first creates some unique properties.

Static analysis from top to bottom #

Since ribs architecture makes use of dependency injection, inheritance, and builder pattern, we are given very strong static analysis of the entire codebase from top to bottom. Compare this to using context to pass services through the widget tree, a common practice in Flutter, where the order of the components is always statically correct but can break an app. The justification of this is to allow for easy refactoring, something that is extremely rare in ribs architecture.

Refactoring your business, not your views #

Any time you refactor an app built on the ribs architecture, it seems that you are fundamentally refactoring the business logic and therefore the business itself. It's rare to refactor a business, so the codebase should remain fairly stable. If you're looking to update a view, that isn't really a refactor in ribs. See below.

A/B testing, not refactoring #

If you want to update a view, you just create a copy of an existing rib with a view and modify the view. Since the new rib conforms to the same interface as the old one, it is fully interchangeable and the business logic of the app never changed. This new rib/view can be enabled via flags for A/B testing, incremental migration, or even providing alternative views for different markets.

Deep linking tied to business logic #

Typically deep linking would throw you into a certain view. Deep linking with ribs is different. You use a Workflow to progress down the tree, which allows you to do things like create dormant deeplinks that will wait for the customer to end up in a certain customer state before firing off an in-app event. Imagine creating a deeplink that causes the app to wait for someone to be looking for a ride before offering them a coupon, instead of just sending them to a page of a coupon.

Services as global state #

Services are passed through the tree and are stateful. For example, it seems to be preffered if ribs don't hold an auth token, but an AuthenticationService would, and it would make it available to the tree. So as you can see, ribs are only concerned with business logic state, ie LoggedIn vs LoggedOut. It's not so concerned with implementation details like auth token. Only services appear to be concerned with those details. These details are still not clear to me, so this part of the docs might change.

Contributing #

This framework should be usable today, since it conforms to all of the uber/ribs Swift test coverage, but it is not battle tested. Feel free to play around with it, make issues, and feel free to make PRs. My goal is to use this framework for research, but ideally the community will move it towards being production ready.

This framework does currently depend on Flutter but if someone wants to make it work outside the Flutter framework I would be happy to accept discuss options in the issues. I'm not sure if this framework would work well for backend applications but I'd be curious to see what backend devs think, and if they believe there is merit, I would happily work with them to make this a pure Dart package.

TODO #

  • Examples, based on Uber's TicTacToe example
  • Code generation utilities
  • Leak detection

[0.1.0] - October 9, 2019

  • Research only initial release.

[0.1.1] - October 9, 2019

  • Description

example/README.md

example #

A new Flutter project.

Getting Started #

This project is a starting point for a Flutter application.

A few resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  ribs: ^0.1.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:ribs/ribs.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
12
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
81
Overall:
Weighted score of the above. [more]
52
Learn more about scoring.

We analyzed this package on Nov 11, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.6

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Format lib/src/componentized_builder.dart.

Run flutter format to format lib/src/componentized_builder.dart.

Format lib/src/interactor.dart.

Run flutter format to format lib/src/interactor.dart.

Format lib/src/launch_router.dart.

Run flutter format to format lib/src/launch_router.dart.

Fix additional 5 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/multi_stage_componentized_builder.dart (Run flutter format to format lib/src/multi_stage_componentized_builder.dart.)
  • lib/src/router.dart (Run flutter format to format lib/src/router.dart.)
  • lib/src/viewable_router.dart (Run flutter format to format lib/src/viewable_router.dart.)
  • lib/src/worker/worker.dart (Run flutter format to format lib/src/worker/worker.dart.)
  • lib/src/workflow/workflow.dart (Run flutter format to format lib/src/workflow/workflow.dart.)

Maintenance suggestions

The package description is too short. (-19 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
rxdart ^0.22.3 0.22.6
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test