Ribs: [Question] Mutate within RIB vs Attach/Detach state-specific RIB

Created on 29 Nov 2018  Â·  8Comments  Â·  Source: uber/RIBs

Say Uber has the following business logic:

Side Menu
- Profile
- UberEats [exists in one country but not another]
Request
- Location refinement [exists in all countries but behavior and looks vary]
- Payment options [exists in all countries but exact options change, list can be provided by some service]

When mapping out the RIBs tree, it seems my options are either:

> Country A
    > Side Menu
        > Profile
    > Request
        > Country A Location refinement
        > Payment options
> Country B
    > Side Menu
        > Profile
        > UberEats
    > Request
        > Country B Location refinement
        > Payment options
> Country C
    ...
...

OR

> Side Menu (attached/detached UberEats based on location)
    > Profile
    > UberEats
> Request
    > Location refinement (switch cases inside to handle location variations)
    > Payment options

They both seem to have severe downsides: either a huge tree with lots of duplication, or RIBs with huge switch cases inside. Is there one that makes more sense to adopt than the other? Or am I missing something and there's a better way to build this RIBs tree?

question

Most helpful comment

A plugin framework would be used when you want to be able to "switch" RIB's (or anything for that matter) on and off. At Uber we use it to rollout features, guard against non-core flows breaking our core functionality i.e being able to switch plugins on/off remotely as well as being able to perform logic like you mentioned above where we have a list of 10 items but only 5 of those items are applicable to a specific scenario.

All 8 comments

The first option is pretty overkill as there's a lot of repetition (and you still have a switch case on the country that you're in). We use your second option everywhere and frankly it's never been a problem. It's in the nature of interactions to take in data and then make decisions on what children to attach, so attaching the UberEats based on some external condition is what interacts are there for.

Got it, option 1 definitely feels wrong given the sheer size from copy pasting.

As for not going straight with option 2, the main reservations were:

  • having switch cases within a RIB where we know the number of cases will keep growing for sure (e.g. locations)
  • seemingly mixing of rules: state of UberEats managed by attach/detach, state of Location refinement managed by itself

To combat the second point above, I've also considered:

> Side Menu (attached/detached UberEats based on location)
    > Profile
    > UberEats
> Request (attached/detached the right RIB based on location)
    > Country A Location refinement
    > Country B Location refinement
    > ...
    > Payment options

Is there a time when you guys take this option 3 approach or is it pretty consistently the mix and switch casing in option 2 above?

Not sure if this applies to your case, but location refinement should most likely be moved to a parent interactor, or have a server made the decision for you. The menu should really just know what features are enabled, and not make the decision whether to enable one particular feature.

At Uber we've created a plugin framework for this (and to tackle your first point of growing number of cases). The menu essentially just provides a place where plugins can attach labels onto. Whether a plugin is enabled is the responsibility of the plugin framework.

Not sure if this applies to your case, but location refinement should most likely be moved to a parent interactor, or have a server made the decision for you. The menu should really just know what features are enabled, and not make the decision whether to enable one particular feature.

At Uber we've created a plugin framework for this (and to tackle your first point of growing number of cases). The menu essentially just provides a place where plugins can attach labels onto. Whether a plugin is enabled is the responsibility of the plugin framework.

Concept wise, I understand. But is there a code example, how to implement the Plugin Point. Just a simply one would help a lot.
screenshot 2018-11-29 at 3 54 25 pm
screenshot 2018-11-29 at 3 54 31 pm

A plugin framework would be used when you want to be able to "switch" RIB's (or anything for that matter) on and off. At Uber we use it to rollout features, guard against non-core flows breaking our core functionality i.e being able to switch plugins on/off remotely as well as being able to perform logic like you mentioned above where we have a list of 10 items but only 5 of those items are applicable to a specific scenario.

I see, but what is the difference between deciding "switch on/off" with a plugin framework vs. with plain RIBs in the interactor like what @artman mentioned above?

It's in the nature of interactions to take in data and then make decisions on what children to attach, so attaching the UberEats based on some external condition is what interacts are there for.

A plugin framework would be used when you want to be able to "switch" RIB's (or anything for that matter) on and off.

I would say the use case for plugins is wider, as plugin points provide a narrow API between parent and its children, with parent remaining agnostic of their existence — it effectively treats all of them as the same thing. But @sbarow is pointing out the key piece of that abstraction: whenever something deviates from the 1 core purpose of the application (it could be additional logic or UI/X) it could and perhaps should be a plugin. Do consult principles of Clean Architecture by Bob Martin.

I see, but what is the difference between deciding "switch on/off" with a plugin framework vs. with plain RIBs in the interactor like what @artman mentioned above?

The way that our plugins work is they check for applicability, if a RIB is applicable then it will be built, if not then nothing happens. With the mentioned approach of using attach/detach you would need to build the RIB's first and then activate them.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

5torm5h4dow picture 5torm5h4dow  Â·  4Comments

ronzohan picture ronzohan  Â·  7Comments

vchernyshov picture vchernyshov  Â·  8Comments

dangthaison91 picture dangthaison91  Â·  8Comments

ZH3057 picture ZH3057  Â·  4Comments