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

front end apis powering fast paced product iterations
SMART_READER_LITE
LIVE PREVIEW

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


slide-1
SLIDE 1

Front-End APIs Powering Fast-Paced Product Iterations

slide-2
SLIDE 2

Speakers

​Jeff Weiner

​Chief Executive Officer

​Aditya Modi

​Staff Software Engineer

​Karthik Ramgopal

​Sr Staff Software Engineer

slide-3
SLIDE 3

Overview

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

slide-4
SLIDE 4

2 Years Ago

slide-5
SLIDE 5

Mobile v/s Desktop

Feed on mobile Feed on desktop Feed on iPad

slide-6
SLIDE 6

Client - Server setup

mobile-frontend-API tablet-frontend-API homepage-frontend-API profile-frontend-API

Android iOS Tablet homepage-desktop-web profile-desktop-web

slide-7
SLIDE 7
  • Huge API surface and diversity
  • No IDL/schema backing API
  • Slow iteration speed

Problems?

slide-8
SLIDE 8

Today

slide-9
SLIDE 9

Mobile v/s Desktop

Feed on mobile Feed on desktop Feed on iPad

slide-10
SLIDE 10

Client - Server setup

flagship-frontend-API

flagship-android flagship-iOS flagship-desktop-web flagship-mobile-web

Rest + JSON over HTTP2

Mid-tier

. . . .

Mid-tier

slide-11
SLIDE 11
  • > 120k QPS
  • ~425 developers
  • ~30 commits per day

Scale

slide-12
SLIDE 12
  • Automated continuous release
  • commit to production in < 3 hours
  • 3 deployments a day

3x3 Deployment

slide-13
SLIDE 13

Modeling

slide-14
SLIDE 14
  • Backed by Strongly Typed Schemas
  • Backward-compatible evolution
  • No endpoint versioning

Principles

slide-15
SLIDE 15

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

Schema definition

iOS Android Web

slide-16
SLIDE 16

Entity Modeling

  • Return - Collection<Card>
slide-17
SLIDE 17

Composite screens

  • Two top level resources

■ Invitations ■ PYMK (People You May Know)

  • 1 network call to fetch both resources

■ Infrastructure level aggregation support

slide-18
SLIDE 18
  • Easy to model
  • Decouple API from UI
  • Client side consistency

Advantages

slide-19
SLIDE 19

Client side consistency

slide-20
SLIDE 20

Client side consistency

  • Why ?

○ Good UX ○ Optimistic writes

slide-21
SLIDE 21

Client side consistency Can you do this auto-magically?

slide-22
SLIDE 22

Client side consistency

Payload Cache

slide-23
SLIDE 23

Client side consistency

Payload Cache

slide-24
SLIDE 24

Client side consistency

Cache Payload

slide-25
SLIDE 25

Everything is awesome, right?

slide-26
SLIDE 26

Takes a long time to ship a feature

API Server

1.5 weeks

iOS

2 weeks

Android

2 weeks

Web

2 weeks

Total time

3.5 weeks

= +

Use case: Introduce a new kind of notification

slide-27
SLIDE 27
  • Create new models for every feature
  • Write code on each client platform
  • Wait for native app release/adoption

Why so long?

slide-28
SLIDE 28

Challenge Cut this down to 1 day!

slide-29
SLIDE 29
  • Quickly build and release notifications
  • Increase user engagement
  • Sweet and sticky, just like honey!

Project Honeycomb

slide-30
SLIDE 30
  • New notifications WITHOUT app updates
  • Client side consistency
  • Stellar runtime performance

Beyond iteration speed...

slide-31
SLIDE 31
  • Model based on how the UI view looks
  • Similar views grouped into 1 template
  • More UI specific logic on API server

View Template API

slide-32
SLIDE 32

Share notification

Share Template

  • PrimaryImage: URL?
  • Title: AttributedString
  • Timestamp: Long
  • ShareImage: URL?
  • ShareTitle: String
  • LikeCount: Long? (Default: 0)
  • CommentCount: Long? (Default: 0)
slide-33
SLIDE 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)
slide-34
SLIDE 34

How about something radically different?

Work Anniversary Template

  • PrimaryImage: URL?
  • Title: AttributedString
  • Timestamp: Long
slide-35
SLIDE 35

Something slightly different again?

Work Anniversary/New Position Template

  • PrimaryImage: URL?
  • Title: AttributedString
  • Timestamp: Long
  • BodyText: AttributedString?
slide-36
SLIDE 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”} }

slide-37
SLIDE 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”} }

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

Client side rendering

slide-39
SLIDE 39

Backward compatibility

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

Drop unknown notification types.

slide-40
SLIDE 40

Backward compatibility

Drop unknown fields based on product needs.

slide-41
SLIDE 41
  • New notification types without client

changes

  • Renders faster on the client

Benefits

slide-42
SLIDE 42

But… Client side Consistency is lost!

slide-43
SLIDE 43

How do we solve this?

slide-44
SLIDE 44

How did we solve the AttributedString problem?

  • Model formatted text
  • Control formatting from the server
  • Impractical to use HTML

AttributedString

slide-45
SLIDE 45

AttributedString schema

AttributedString

  • Text: String
  • Attributes: List[Attribute] BOLD, ITALIC, UNDERLINE etc.

Attribute

  • Type: AttributeType
  • StartIndex: Int
  • Length: Int
  • Metadata: Any?
slide-46
SLIDE 46

Platform specific binding

Infrastructure provided support

iOS Android Web

NSAttributedString Spannable HTML AttributedString

slide-47
SLIDE 47

What if we extended this concept to entity mentions?

Model entity mentions also as a custom formatting specifier.

Profile mention Profile mention

slide-48
SLIDE 48

Introducing TextViewModel

TextViewModel

  • Text: String
  • Attributes: List[TextViewAttribute]

TextViewAttribute

  • Type: TextViewAttributeType
  • StartIndex: Int
  • Length: Int
  • Metadata: Any?
  • Profile: Profile?
  • Job: Job?
  • Company: Company?
  • Course: Course?

Flattened canonical entities as optional fields Similar to AttributedString

slide-49
SLIDE 49

Entity mentions

Entities could be mentioned in different ways.

First Name Full Name Position

slide-50
SLIDE 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.
slide-51
SLIDE 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….} ] } }

slide-52
SLIDE 52
  • Singular and Plurals
  • Possessive forms
  • i10n and i18n

Watch Out

slide-53
SLIDE 53

How about images?

Use the same concept as TextViewModel. Introduce ImageViewModel. ImageViewModel

  • Attributes: List[ImageViewAttribute]

ImageViewAttribute

  • ImageViewAttributeType
  • URL: URL?
  • ResourceName: String?
  • Profile: Profile?
  • Job: Job?
  • Company: Company?
  • Course: Course?

Flattened canonical entities as optional fields

slide-54
SLIDE 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.
slide-55
SLIDE 55

Rendering Images

  • Infra code extracts Image URL out of ImageViewModel
  • Load into platform specific image view.

One Attribute: Regular ImageView Multiple Attributes: GridImageView

slide-56
SLIDE 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

slide-57
SLIDE 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”, ... } }, .... ] }

slide-58
SLIDE 58

Performance considerations (Continued)

All fields from the entities may not be used.

ImageURL First Name and Last Name

slide-59
SLIDE 59

Solution: Deco

Deco is a LinkedIn framework that allows selective projection and decoration of fields.

Profile in TextViewModel ID FirstName LastName Profile in ImageViewModel ID ImageURL Profile in Response ID FirstName LastName ImageURL

slide-60
SLIDE 60

Results

slide-61
SLIDE 61

Improved Developer and Product Velocity

9 new notification types in all of 2016

16 new notification types in May and June 2017

slide-62
SLIDE 62

API model reduction

42 API models for old UI

6 API models for new UI

slide-63
SLIDE 63

Code size reduction

15k LOC app and test code for old UI

3k LOC app and test code for new UI

slide-64
SLIDE 64

Future Direction

  • Extend to other pages in Flagship
  • Extend to other LinkedIn apps like JobSeeker, Recruiter etc.
slide-65
SLIDE 65

Out of scope for this talk

  • Intricate details of client side consistency management
  • Generic Modeling of actions
  • Challenges in migrating from the old notifications API to the new one

Find us after the talk, and we’re happy to chat about this and more.

slide-66
SLIDE 66

Q & A

​amodi@linkedin.com ​https://www.linkedin.com/in/modiaditya/ ​

​Aditya Modi

​kramgopal@linkedin.com ​https://www.linkedin.com/in/karthikrg/ ​ ​

​Karthik Ramgopal