front end apis powering fast paced product iterations
play

Front-End APIs Powering Fast-Paced Product Iterations Speakers - PowerPoint PPT Presentation

Front-End APIs Powering Fast-Paced Product Iterations Speakers Jeff Weiner Aditya Modi Karthik Ramgopal Staff Software Engineer Sr Staff Software Engineer Chief Executive Officer Overview History and evolution of frontend


  1. Front-End APIs Powering Fast-Paced Product Iterations

  2. Speakers ​ Jeff Weiner ​ Aditya Modi ​ Karthik Ramgopal ​ Staff Software Engineer ​ Sr Staff Software Engineer ​ Chief Executive Officer

  3. Overview History and evolution of frontend APIs at LinkedIn Our API structure today Learnings and results Sneak peek at the future

  4. 2 Years Ago

  5. Mobile v/s Desktop Feed on mobile Feed on iPad Feed on desktop

  6. Client - Server setup mobile-frontend-API tablet-frontend-API homepage-frontend-API profile-frontend-API iOS homepage-desktop-web Android Tablet profile-desktop-web

  7. • Huge API surface and diversity Problems? • No IDL/schema backing API • Slow iteration speed

  8. Today

  9. Mobile v/s Desktop Feed on mobile Feed on iPad Feed on desktop

  10. Client - Server setup . . . . Mid-tier Mid-tier flagship-frontend-API Rest + JSON over HTTP2 flagship-mobile-web flagship-android flagship-iOS flagship-desktop-web

  11. • > 120k QPS Scale • ~425 developers • ~30 commits per day

  12. • Automated continuous release 3x3 Deployment • commit to production in < 3 hours • 3 deployments a day

  13. Modeling

  14. • Backed by Strongly Typed Schemas Principles • Backward-compatible evolution • No endpoint versioning

  15. Schema definition @interface TestRecord : NSObject iOS @property(nonnull, copy) NSString *id; @property(nullable, copy) NSString *name; { @end "type": "record", "name": "TestRecord", "namespace": "com.linkedin.test", "doc": "Test", "fields": [ { class TestRecord { "name": "id", "type": "String", Android @NonNull public final String id; "doc": "ID" @Nullable public final String name; }, { } "name": "name", "type": "String", "doc": "Name", “optional”: true }, ] } export default DS.Model.extend({ Web id: DS.attr(‘string’), name: DS.attr(‘string’) });

  16. Entity Modeling • Return - Collection<Card>

  17. Composite screens ● Two top level resources ■ Invitations ■ PYMK (People You May Know) ● 1 network call to fetch both resources ■ Infrastructure level aggregation support

  18. • Easy to model Advantages • Decouple API from UI • Client side consistency

  19. Client side consistency

  20. Client side consistency • Why ? ○ Good UX ○ Optimistic writes

  21. Client side consistency Can you do this auto-magically?

  22. Client side consistency Payload Cache

  23. Client side consistency Payload Cache

  24. Client side consistency Cache Payload

  25. Everything is awesome, right?

  26. Takes a long time to ship a feature Use case: Introduce a new kind of notification iOS 2 weeks = + API Server Total time Android 1.5 weeks 3.5 weeks 2 weeks Web 2 weeks

  27. • Create new models for every feature Why so long? • Write code on each client platform • Wait for native app release/adoption

  28. Challenge Cut this down to 1 day!

  29. Project Honeycomb • Quickly build and release notifications • Increase user engagement • Sweet and sticky, just like honey!

  30. Beyond iteration speed... • New notifications WITHOUT app updates • Client side consistency • Stellar runtime performance

  31. • Model based on how the UI view looks View Template API • Similar views grouped into 1 template • More UI specific logic on API server

  32. Share notification Share Template ● PrimaryImage: URL? ● Title: AttributedString ● Timestamp: Long ● ShareImage: URL? ● ShareTitle: String ● LikeCount: Long? (Default: 0) ● CommentCount: Long? (Default: 0)

  33. Now let’s look at a slightly different notification Modify Share Template ● PrimaryImage: URL? ● Title: AttributedString ● Timestamp: Long ● ShareImage: URL? ● ShareTitle: String AttributedString ● ShareSubtitle: AttributedString? ● LikeCount: Long? (Default: 0) ● CommentCount: Long? (Default: 0)

  34. How about something radically different? Work Anniversary Template ● PrimaryImage: URL? ● Title: AttributedString ● Timestamp: Long

  35. Something slightly different again? Work Anniversary/New Position Template ● PrimaryImage: URL? ● Title: AttributedString ● Timestamp: Long ● BodyText: AttributedString?

  36. How do we return a heterogeneous list? • Use Rest.li paginated collections . Differentiate between items using a Union . • JSON payload structure: { “elements” : [ {“Share”: {“Title”: “Sarah Clatterbuck shared a … ”, ...}}, {“Anniversary”: {“Title”: “Congratulate Nitish Jha … ”, ...}}, .... ], “paging”: { “start” : 0, “count”: 10, “paginationToken”: “xydsad”} }

  37. Minor payload optimization • Embed the type into the payload to reduce nesting. • JSON payload structure: { “elements” : [ {“Type”: “Share”, “Title”: “Sarah Clatterbuck shared a … ”, ...}, {“Type”: “Anniversary”, “Title”: “Congratulate Nitish Jha … ”, ...}, .... ], “paging”: { “start” : 0, “count”: 10, “paginationToken”: “xydsad”} }

  38. • Code-generated response parser Client side rendering • Bind model to native views • Write once * per layout, reuse.

  39. Backward compatibility Drop unknown notification types. { “elements” : [ {“Stat”: {“Title”: “Your Profile...”, ...}}, {“JYMBII”: {“Title”: “5 Jobs you”, ...}}, {“Share”: {“Title”: “Swati Mathur...”, ...}}, .... ], “paging”: { “start” : 0, “count”: 10, “paginationToken”: “xydsad”} }

  40. Backward compatibility Drop unknown fields based on product needs.

  41. • New notification types without client Benefits changes • Renders faster on the client

  42. But… Client side Consistency is lost!

  43. How do we solve this?

  44. How did we solve the AttributedString problem? • Model formatted text AttributedString • Control formatting from the server • Impractical to use HTML

  45. AttributedString schema AttributedString ● Text: String ● Attributes: List[Attribute] BOLD, ITALIC, UNDERLINE etc. Attribute ● Type: AttributeType ● StartIndex: Int ● Length: Int ● Metadata: Any?

  46. Platform specific binding Infrastructure provided support NSAttributedString iOS AttributedString Spannable Android HTML Web

  47. What if we extended this concept to entity mentions? Model entity mentions also as a custom formatting specifier. Profile mention Profile mention

  48. Introducing TextViewModel TextViewModel ● Text: String ● Attributes: List[TextViewAttribute] TextViewAttribute Similar to AttributedString ● Type: TextViewAttributeType ● StartIndex: Int ● Length: Int ● Metadata: Any? ● Profile: Profile? Flattened canonical entities as optional fields ● Job: Job? ● Company: Company? ● Course: Course?

  49. Entity mentions Entities could be mentioned in different ways. Full Name First Name Position

  50. TextViewAttributeType TextViewAttributeType ● PROFILE_FIRST_NAME ● PROFILE_FULL_NAME ● PROFILE_HEADLINE ● PROFILE_DISTANCE ● COMPANY_NAME ● COMPANY_HEADLINE ● JOB_TITLE ● …. If a particular type is used, then the corresponding entity is populated by the server. ● PROFILE_XXX types will populate the profile field for example with the corresponding profile.

  51. Backward compatibility++ Old clients cannot handle new mention types. Always send Raw text though redundant . { “title” : { “Text”: “ Sarah Clatterbuck shared this”, “Attributes”: [ {“Type”: “PROFILE_FULL_NAME”, “StartIndex”: 0 … .} ] } }

  52. • Singular and Plurals Watch Out • Possessive forms • i10n and i18n

  53. How about images? Use the same concept as TextViewModel . Introduce ImageViewModel . ImageViewModel ● Attributes: List[ImageViewAttribute] ImageViewAttribute ● ImageViewAttributeType ● URL: URL? ● ResourceName: String? ● Profile: Profile? Flattened canonical entities as optional fields ● Job: Job? ● Company: Company? ● Course: Course?

  54. ImageViewAttributeType ImageViewAttributeType ● URL ● RESOURCE_NAME ● PROFILE_IMAGE ● PROFILE_BACKGROUND ● COMPANY_IMAGE ● …. If a particular type is used, then the corresponding entity is populated by the server. ● PROFILE_XXX types will populate the profile field for example with the corresponding profile. ● URL type will populate the image URL ● RESOURCE_NAME will populate the pre-canned resource name.

  55. Rendering Images ● Infra code extracts Image URL out of ImageViewModel ● Load into platform specific image view. One Attribute: Regular ImageView Multiple Attributes: GridImageView

  56. Performance considerations Entities may repeat multiple times within the same notification causing payload size bloat. Tim’s Profile in ImageViewModel Tim’s Profile in TextViewModel

  57. Solution: Response Normalization All canonical entities have a unique ID. Use a JSON API like response format . { “data” : { “Profile”: “ profile:123 ”, ... }, “included”: [ { “id” : “profile:123”, “firstName” : “Tim”, “LastName” : “Jurka”, ... } }, .... ] }

Recommend


More recommend