Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Working effectively at scale

Working effectively at scale

Presented at BA:Swiftable in November, 2019.

Francisco Díaz

November 29, 2019
Tweet

More Decks by Francisco Díaz

Other Decks in Programming

Transcript

  1. Working
    e!ectively
    at scale

    View Slide

  2. Francisco
    Díaz
    franciscodiaz.cl - @fco_diaz

    View Slide

  3. Startups
    2011 - 2017

    View Slide

  4. Airbnb
    2017 - today

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. organizations ... are
    constrained to produce
    designs which are copies of
    the communication structures
    of these organizations
    — Conway's law

    View Slide

  15. How do you
    divide
    your codebase?

    View Slide

  16. Architectural layer

    View Slide

  17. User Flow

    View Slide

  18. What about
    Airbnb?

    View Slide

  19. View Slide

  20. 1 million lines
    of Swift

    View Slide

  21. ~80 commits
    to master on any given day to the repo (Android + iOS)

    View Slide

  22. Bigger
    buckets

    View Slide

  23. View Slide

  24. A user should be
    able to wishlist a
    listing from the
    booking flow

    View Slide

  25. How do they
    relate
    with each other?

    View Slide

  26. View Slide

  27. View Slide

  28. View Slide

  29. 50 min
    local clean builds

    View Slide

  30. ~30 min
    !

    View Slide

  31. Buck
    HTTP Cache
    https://github.com/airbnb/BuckSample

    View Slide

  32. View Slide

  33. ~5 min
    !

    View Slide

  34. View Slide

  35. View Slide

  36. Dependency
    inversion

    View Slide

  37. ‣High-level modules should not depend on low-
    level modules. Both should depend on abstractions.
    ‣Abstractions should not depend on details. Details
    (concrete implementations) should depend on
    abstractions.

    View Slide

  38. View Slide

  39. A user should be
    able to wishlist a
    listing from the
    booking flow

    View Slide

  40. View Slide

  41. Easy!
    WishListDataSource
    + interface!

    View Slide

  42. View Slide

  43. WishListDataSource
    is still visible

    View Slide

  44. View Slide

  45. Socializing
    best practices

    View Slide

  46. !

    View Slide

  47. +60
    iOS developers

    View Slide

  48. Automating
    best practices

    View Slide

  49. Groups
    Modules

    View Slide

  50. Groups
    Modules
    Module Types

    View Slide

  51. Module Types
    Feature + Interface
    Service + Interface

    View Slide

  52. Feature
    A screen or a flow
    in the app

    View Slide

  53. Service
    Manage shared
    state or resources

    View Slide

  54. View Slide

  55. View Slide

  56. How do we
    enforce these
    best practices?

    View Slide

  57. /services
    /service_interfaces
    /features
    /feature_interfaces

    View Slide

  58. def service_interface(
    name,
    deps):
    max_visibility = [
    "//ios/feature_interfaces/...",
    "//ios/features/...",
    "//ios/service_interfaces/...",
    "//ios/services/...",
    ]

    View Slide

  59. service_interface(
    name = "Networking",
    deps = [
    "//ios/service_interfaces/Logging",
    ],
    )

    View Slide

  60. feature(
    name = "Booking",
    deps = [
    "//ios/service_interfaces/Networking",
    "//ios/service_interfaces/WishListService",
    ],
    )

    View Slide

  61. iOS Platform

    View Slide

  62. Module creation
    needs to be easy

    View Slide

  63. View Slide

  64. View Slide

  65. rake
    make:module

    View Slide

  66. > Provide the type of module you want to create:
    1: Non Platform
    2: Feature
    3: Feature Interface
    4: Service
    5: Service Interface
    4
    > New module name:
    Swiftable
    > Provide a high level description of this module:
    This is a module to present at Swiftable

    View Slide

  67. Buck
    Human readable dependencies
    https://github.com/airbnb/BuckSample

    View Slide

  68. feature(
    name = "Booking",
    deps = [
    "//ios/service_interfaces/Networking",
    "//ios/service_interfaces/WishListService",
    "//ios/feature_interfaces/HelpCenter",
    ],
    )

    View Slide

  69. View Slide

  70. Feature
    A screen or a flow
    in the app

    View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. Dev Apps

    View Slide

  75. ~1 min
    Dev Apps

    View Slide

  76. Big buckets
    Small
    playgrounds

    View Slide

  77. View Slide

  78. How do we
    get there?

    View Slide

  79. ~100 modules
    One module type: /libraries

    View Slide

  80. libraries/AirbnbBooking
    libraries/AirbnbBusinessTravel
    libraries/AirbnbHelpCenter
    libraries/AirbnbListings
    libraries/AirbnbNetworking
    libraries/AirbnbWishLists
    ...

    View Slide

  81. Before iOS Platform
    /libraries

    View Slide

  82. On the iOS Platform
    /services
    /service_interfaces
    /features
    /feature_interfaces

    View Slide

  83. How to get
    everybody
    on the iOS Platform?

    View Slide

  84. Remove libraries/
    and start over

    View Slide

  85. !

    View Slide

  86. Progressively
    migrate

    View Slide

  87. Let's
    migrate
    WishLists Data Source

    View Slide

  88. libraries/WishLists

    View Slide

  89. View Slide

  90. View Slide

  91. View Slide

  92. What are the
    dependency rules
    for libraries/?

    View Slide

  93. View Slide

  94. Inbound dependencies
    Outbound dependencies

    View Slide

  95. Inbound dependencies
    Outbound dependencies

    View Slide

  96. View Slide

  97. The interface module has
    stricter rules

    View Slide

  98. Migrate all the call
    sites

    View Slide

  99. As the owner of WishLists
    We don't
    control
    these

    View Slide

  100. View Slide

  101. Calculated
    tech debt

    View Slide

  102. Inbound dependencies
    Outbound dependencies

    View Slide

  103. View Slide

  104. we know our usage
    of Networking

    View Slide

  105. We control our dependencies

    View Slide

  106. Allow inbound dependencies from libraries/
    Don't allow outbound dependencies to libraries/

    View Slide

  107. libraries/ has access to the
    iOS Platform

    View Slide

  108. The iOS Platform doesn't
    have access to libraries/

    View Slide

  109. Code on
    the iOS Platform
    has good
    boundaries

    View Slide

  110. while we allow for
    easier migration

    View Slide

  111. def service_interface(
    name,
    visibility = []):
    max_visibility = [
    "//ios/feature_interfaces/...",
    "//ios/features/...",
    "//ios/service_interfaces/...",
    "//ios/services/...",
    ]
    add_visibility_for_legacy_module_structure(max_visibility)

    View Slide

  112. def add_visibility_for_legacy_module_structure(visibility):
    visibility.extend([
    "//ios/libraries/...",
    ])

    View Slide

  113. We started
    migrating
    from the bottom up

    View Slide

  114. Try it
    ourselves
    !rst

    View Slide

  115. Pilot
    with others teams

    View Slide

  116. Should I
    implement
    this?

    View Slide

  117. Most likely
    NO

    View Slide

  118. There's no
    silver bullet

    View Slide

  119. Adapt

    View Slide

  120. Summary
    1. Figure out where you're struggling
    2.Create and document best practices
    3.Automate best practices where needed

    View Slide

  121. ¡Gracias!
    franciscodiaz.cl/talks

    View Slide