Ribs: [Questions] Best practices for modular codebase

Created on 19 Oct 2018  Â·  7Comments  Â·  Source: uber/RIBs

Not actionable. Please keep going as community wiki.

RIBs provide an extraordinary level of decoupling to the code, but there is always more separation that can improve agility in a large teams. Splitting the project into modules (e.g. Xcode sub projects and frameworks) is one of those improvements and I’m hoping for a bit of input from the RIBs authors on how to strike a right balance between the two without (pre-)over-optimizing.

question

Most helpful comment

At Uber, we use a large number of modules (frameworks) to keep the code organized and split between teams. The modules are meant to be focussed on one set of features (often this aligns with a feature team, but ownership can change over time). For example, we have a Pool module for UberPOOL features, and one for ScheduledRides.

The "core" functionality of the app lives in a module. This depends on another module that insulates the core from all the feature modules. Ideally, a feature module would not be allowed to import another feature module (true for our newer apps, not quite there for some older ones). If a feature modules does need to talk to a sibling feature, we use dependency inversion, and the insulating module I mentioned wires one feature to the other so that they don't need the direct import.

Below these feature modules live some modules that may be shared across multiple feature sets.

This is useful at our scale. For your use-case, this many modules may be overkill. The dependency inversion also adds a bunch of boilerplate that may be annoying at a smaller scale (it's annoying at a large scale too, but we feel it's worth it).

All 7 comments

+1

At Uber, we use a large number of modules (frameworks) to keep the code organized and split between teams. The modules are meant to be focussed on one set of features (often this aligns with a feature team, but ownership can change over time). For example, we have a Pool module for UberPOOL features, and one for ScheduledRides.

The "core" functionality of the app lives in a module. This depends on another module that insulates the core from all the feature modules. Ideally, a feature module would not be allowed to import another feature module (true for our newer apps, not quite there for some older ones). If a feature modules does need to talk to a sibling feature, we use dependency inversion, and the insulating module I mentioned wires one feature to the other so that they don't need the direct import.

Below these feature modules live some modules that may be shared across multiple feature sets.

This is useful at our scale. For your use-case, this many modules may be overkill. The dependency inversion also adds a bunch of boilerplate that may be annoying at a smaller scale (it's annoying at a large scale too, but we feel it's worth it).

RIBs is awesome! I have few questions about how Uber manages service APIs as there are some similar services among Rider app and UberEats, such as destination searching (i.e. _Where to_).

Is there a separate module to hold these services for sharing among two apps or two sets of services in each app?

Just a couple of follow ups on process:

  • Xcode is eager to set up source control — do you use git submodules? I've heard they are fragile.
  • How do plugins get imported at higher-levels e.g. Root plugin mount point that runs as soon as the app starts? (I assume plugins within feature, like Onboarding are encapsulated.)
  • External dependency management: Podfiles for each module? Single Podfile that works with each module's targets? Something else?
  • If you use CocoaPods, have you seen any issues with magic changes to the project / workspace?

I've updated the original issue hoping we can keep this discussion going for a bit and hopefully it will find its way to a wiki page or blog post. Otherwise @uber feel free to close as non-actionable/answered.

RIBs is awesome! I have few questions about how Uber manages service APIs as there are some similar services among Rider app and UberEats, such as destination searching (i.e. _Where to_).

Is there a separate module to hold these services for sharing among two apps or two sets of services in each app?

A wrapper to talk to our end-points are auto-generated, as are all the models that the JSON get deserialized into. We use Thrift (https://thrift.apache.org) specs to specify all the API endpoint details.

Yes, there are models shared across our apps. There are both low-level libraries (like storage or analytics) as well as modules at the level you're asking about. They aren't usually just the code to talk to the backend, but includes the UI as well.

Just a couple of follow ups on process:

  • Xcode is eager to set up source control — do you use git submodules? I've heard they are fragile.
  • How do plugins get imported at higher-levels e.g. Root plugin mount point that runs as soon as the app starts? (I assume plugins within feature, like Onboarding are encapsulated.)
  • External dependency management: Podfiles for each module? Single Podfile that works with each module's targets? Something else?
  • If you use CocoaPods, have you seen any issues with magic changes to the project / workspace?

I've updated the original issue hoping we can keep this discussion going for a bit and hopefully it will find its way to a wiki page or blog post. Otherwise @uber feel free to close as non-actionable/answered.

We use git. We do not use submodules.

I'm not quite sure I understand the question about importing at higher levels.

We use buck (https://buckbuild.com) to manage our modules and generate Xcode project files.

We don't use CocoaPods. All of our iOS code lives in a monrepo. There's an overview of buck+monorepo+no cocoa pods here : https://eng.uber.com/ios-monorepo/

Closing thread as stale.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ronzohan picture ronzohan  Â·  7Comments

almozavr picture almozavr  Â·  4Comments

ZacSweers picture ZacSweers  Â·  6Comments

ZH3057 picture ZH3057  Â·  4Comments

kronik picture kronik  Â·  3Comments