SlideShare a Scribd company logo
Creating a Facebook Clone - Part XX
Notification is the last client data class that maps to an entity. In that sense it will get more interesting after this point…
@Entity
public class Notification {
@Id
private String id;
@ManyToOne
private User user;
private String text;
private String reaction;
private int reactionColor;
private long date;
private boolean wasRead;
private String postId;
private String commentId;
public Notification() {
id = UUID.randomUUID().toString();
}
public NotificationDAO getDAO() {
return new NotificationDAO(id, user.getDAO(), text, reaction,
reactionColor, date, wasRead, postId, commentId);
Notification
The class is pretty standard

Again these map directly to the client side data
@Entity
public class Notification {
@Id
private String id;
@ManyToOne
private User user;
private String text;
private String reaction;
private int reactionColor;
private long date;
private boolean wasRead;
private String postId;
private String commentId;
public Notification() {
id = UUID.randomUUID().toString();
}
public NotificationDAO getDAO() {
return new NotificationDAO(id, user.getDAO(), text, reaction,
reactionColor, date, wasRead, postId, commentId);
Notification
A notification might relate to a post or a comment so having its id here might be useful to launch said post when the notification is clicked
private long date;
private boolean wasRead;
private String postId;
private String commentId;
public Notification() {
id = UUID.randomUUID().toString();
}
public NotificationDAO getDAO() {
return new NotificationDAO(id, user.getDAO(), text, reaction,
reactionColor, date, wasRead, postId, commentId);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
Notification
The constructor and DAO match the convention of the other classes
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public boolean isWasRead() {
return wasRead;
}
public void setWasRead(boolean wasRead) {
this.wasRead = wasRead;
}
public String getPostId() {
return postId;
}
public void setPostId(String postId) {
this.postId = postId;
}
public String getCommentId() {
return commentId;
}
public void setCommentId(String commentId) {
this.commentId = commentId;
}
}
Notification
The rest is again getters & setters
public class NotificationDAO {
private String id;
private UserDAO user;
private String text;
private String reaction;
private int reactionColor;
private long date;
private boolean wasRead;
private String postId;
private String commentId;
public NotificationDAO() {
}
public NotificationDAO(String id, UserDAO user, String text,
String reaction, int reactionColor, long date, boolean wasRead,
String postId, String commentId) {
this.id = id;
this.user = user;
this.text = text;
this.reaction = reaction;
NotificationDAO
The next step is the DAO which again maps very closely.

There is literally nothing special here, we might as well have used the Notification entity to some degree.
return date;
}
public void setDate(long date) {
this.date = date;
}
public boolean isWasRead() {
return wasRead;
}
public void setWasRead(boolean wasRead) {
this.wasRead = wasRead;
}
public String getPostId() {
return postId;
}
public void setPostId(String postId) {
this.postId = postId;
}
public String getCommentId() {
return commentId;
}
public void setCommentId(String commentId) {
this.commentId = commentId;
}
}
NotificationDAO
As you can see the rest of the code is classic boilerplate
Newsfeed
✦Why Newsfeed Entity?
✦Consistency
✦Tune Experience
© Codename One 2017 all rights reserved
This is getting a bit more interesting... Newsfeed represents the feed for a user. I could have just created a really complex join query on Post and called it a day but that's
problematic. The newsfeed isn't just a list of posts based on date. It's something that includes a complex algorithm behind it. Running that algorithm every time the user
pages through data might be very expensive.

Furthermore, changes to the algorithm shouldn't impact past placements. We'd want consistency and we'd also like to have a log of "what did the user see". In that
sense constructing the newsfeed as an entity in its own right makes a lot of sense.

We can place the articles into the newsfeed using a sort order that makes sense for a specific user without impacting everyone. We can tune and experiment with article
placement algorithms easily because our processing can be done offline on the table itself.
@Entity
public class Newsfeed {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
Newsfeed
This is getting a bit more interesting... Newsfeed represents the feed for a user. I could have just created a really complex join query on Post and called it a day but that's
problematic. The newsfeed isn't just a list of posts based on date. It's something that includes a complex algorithm behind it. Running that algorithm every time the user
pages through data might be very expensive.

Furthermore, changes to the algorithm shouldn't impact past placements. We'd want consistency and we'd also like to have a log of "what did the user see". In that
sense constructing the newsfeed as an entity in its own right makes a lot of sense.

We can place the articles into the newsfeed using a sort order that makes sense for a specific user without impacting everyone. We can tune and experiment with article
placement algorithms easily because our processing can be done offline on the table itself.

We use an auto-increment numeric id since this object isn't exposed to the client side at any stage the id doesn't matter as much and this id type is faster
@Entity
public class Newsfeed {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
Newsfeed
Every entry within the newsfeed has a user & post. Notice that the user is probably a different user from the one who submitted the post
@Entity
public class Newsfeed {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
Newsfeed
postDay is the number of days since epoch. This is useful for sorting, I want todays posts to always come before yesterdays posts even if they are higher quality
@Entity
public class Newsfeed {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
Newsfeed
Timestamp is also used for the sort but to a lesser degree
@Entity
public class Newsfeed {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
Newsfeed
Rank can be manipulated by a ranking algorithm to push good posts up within the day
private User parent;
@ManyToOne
private Post entry;
private long postDay;
private long postTimestamp;
private int rank;
public Newsfeed() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getParent() {
return parent;
}
public void setParent(User parent) {
this.parent = parent;
}
public Post getEntry() {
return entry;
}
Newsfeed
We have no DAO. We don't need it, this is a server side object
return entry;
}
public void setEntry(Post entry) {
this.entry = entry;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public long getPostDay() {
return postDay;
}
public void setPostDay(long postDay) {
this.postDay = postDay;
}
public long getPostTimestamp() {
return postTimestamp;
}
public void setPostTimestamp(long postTimestamp) {
this.postTimestamp = postTimestamp;
}
}
Newsfeed
We do need the getters/setters though for the entity
public interface NewsfeedRepository extends CrudRepository<Newsfeed, Long>{
@Query("select n from Newsfeed n where n.parent.authtoken = ?1")
public Page<Newsfeed> findNewsfeedForUser(
String auth, Pageable page);
}
NewsfeedRepository
The Newsfeed also requires a CrudRepository class. We need to use the auth and not the ID to prevent a case where another user gets a peek at my feed which might
include "friend only" posts

With that we only have one more item...
@Entity
public class ShadowUser {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String fullName;
private String phone;
private String email;
private String secondaryPhone;
@ManyToOne
private User owner;
public ShadowUser() {
}
public ShadowUser(ShadowUserDAO dao, User owner) {
this.fullName = dao.getFullName();
this.phone = dao.getPhone();
this.email = dao.getEmail();
this.secondaryPhone = dao.getSecondaryPhone();
ShadowUser
The shadow user is a "potential" user of whom we have knowledge but he might not be in the social network.

Do you ever wonder how Facebook seems to know so much about you before you even signed up? They keep suggesting people that they can't possibly know about...

Well, here's one of the tricks they use. When you agree to synchronize your contacts to Facebook (and they nag a lot about this) they upload the whole thing and store it.
If you have friends that are already in Facebook you'll get suggestions instantly but they keep everything anyway.

When one of your contacts signs up for Facebook they notice that you know and instantly add a suggestion. This works in reverse too, someone has your email or phone
number so you'd see them as a suggestion.

They go even further by associations e.g. you might have a connection like that through a 3rd party so even if you never synchronized contacts they'd still know.

I chose to implement a relatively simple version of this and didn't include all the meta-data that Facebook probably stores. This is mostly a simple proof of concept that
should be enough for us to provide friend suggestions.

We again use auto-increment for an internal entity
@Entity
public class ShadowUser {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String fullName;
private String phone;
private String email;
private String secondaryPhone;
@ManyToOne
private User owner;
public ShadowUser() {
}
public ShadowUser(ShadowUserDAO dao, User owner) {
this.fullName = dao.getFullName();
this.phone = dao.getPhone();
this.email = dao.getEmail();
this.secondaryPhone = dao.getSecondaryPhone();
ShadowUser
This is the meta-data we gather for a user, there is obviously a lot more we can gather
@Entity
public class ShadowUser {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String fullName;
private String phone;
private String email;
private String secondaryPhone;
@ManyToOne
private User owner;
public ShadowUser() {
}
public ShadowUser(ShadowUserDAO dao, User owner) {
this.fullName = dao.getFullName();
this.phone = dao.getPhone();
this.email = dao.getEmail();
this.secondaryPhone = dao.getSecondaryPhone();
ShadowUser
This is the user who uploaded the data so if the data in this record matches me then I probably know the owner
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String fullName;
private String phone;
private String email;
private String secondaryPhone;
@ManyToOne
private User owner;
public ShadowUser() {
}
public ShadowUser(ShadowUserDAO dao, User owner) {
this.fullName = dao.getFullName();
this.phone = dao.getPhone();
this.email = dao.getEmail();
this.secondaryPhone = dao.getSecondaryPhone();
this.owner = owner;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
ShadowUser
We have a DAO object but this DAO is write only. So the entity isn't exposed to the outside world but the outside world is exposed to the entity. That’s why we don’t have
a getDAO method!

We do have a special constructor type that makes adding a new ShadowUser easier.
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSecondaryPhone() {
return secondaryPhone;
}
public void setSecondaryPhone(String secondaryPhone) {
this.secondaryPhone = secondaryPhone;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
}
ShadowUser
As with the other entities the rest is just setters & getters.
public class ShadowUserDAO {
private String fullName;
private String phone;
private String email;
private String secondaryPhone;
public ShadowUserDAO() {
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
ShadowUserDAO
In a sense the ShadowUserDAO is a bit different from the other DAO’s.

This is a pretty standard DAO with two big omissions: ID & Owner both of which are missing…

The ID is redundant as it's auto generated, the owner is also redundant as it's always the user that uploaded the contacts. There is no point of including either one of
these values in the DAO as they won't arrive through it from the client.
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSecondaryPhone() {
return secondaryPhone;
}
public void setSecondaryPhone(String secondaryPhone) {
this.secondaryPhone = secondaryPhone;
}
}
ShadowUserDAO
The rest of the DAO is just getters and setters
public interface ShadowUserRepository extends
CrudRepository<ShadowUser, Long> {
@Query("select n from ShadowUser n where n.owner.authtoken = ?1")
public List<ShadowUser> findShadowUsers(String auth);
@Query("select n from ShadowUser n where n.phone = ?1 or "
+ "n.secondaryPhone = ?1")
public List<ShadowUser> findByPhone(String phone);
@Query("select n from ShadowUser n where n.email = ?1")
public List<ShadowUser> findByEmail(String email);
@Query("select count(n) from ShadowUser n where "
+ "n.owner.authtoken = ?1")
public Long countByUser(String auth);
@Query("select n from ShadowUser n where n.owner.authtoken = ?1 and "
+ "n.fullName = ?2")
public List<ShadowUser> findByFullName(String auth, String fullName);
}
ShadowUserRepository
In this case the CrudRepository is actually pretty interesting. We need it for the case where we create a new user or update data. We need to find all the related users.

Given a users phone we look through the database for users who might have that phone in their contacts, the same is true for email
public interface ShadowUserRepository extends
CrudRepository<ShadowUser, Long> {
@Query("select n from ShadowUser n where n.owner.authtoken = ?1")
public List<ShadowUser> findShadowUsers(String auth);
@Query("select n from ShadowUser n where n.phone = ?1 or "
+ "n.secondaryPhone = ?1")
public List<ShadowUser> findByPhone(String phone);
@Query("select n from ShadowUser n where n.email = ?1")
public List<ShadowUser> findByEmail(String email);
@Query("select count(n) from ShadowUser n where "
+ "n.owner.authtoken = ?1")
public Long countByUser(String auth);
@Query("select n from ShadowUser n where n.owner.authtoken = ?1 and "
+ "n.fullName = ?2")
public List<ShadowUser> findByFullName(String auth, String fullName);
}
ShadowUserRepository
We check if a user has uploaded contacts in the past by counting his entries, assuming he has we will try to merge the data
public interface ShadowUserRepository extends
CrudRepository<ShadowUser, Long> {
@Query("select n from ShadowUser n where n.owner.authtoken = ?1")
public List<ShadowUser> findShadowUsers(String auth);
@Query("select n from ShadowUser n where n.phone = ?1 or "
+ "n.secondaryPhone = ?1")
public List<ShadowUser> findByPhone(String phone);
@Query("select n from ShadowUser n where n.email = ?1")
public List<ShadowUser> findByEmail(String email);
@Query("select count(n) from ShadowUser n where "
+ "n.owner.authtoken = ?1")
public Long countByUser(String auth);
@Query("select n from ShadowUser n where n.owner.authtoken = ?1 and "
+ "n.fullName = ?2")
public List<ShadowUser> findByFullName(String auth, String fullName);
}
ShadowUserRepository
We use the full name of the user when merging contact data.

With that we finished all the entities and we are finally ready to move up the food chain to the service layer!

More Related Content

Similar to Creating a Facebook Clone - Part XX - Transcript.pdf

Green dao 3.0
Green dao 3.0Green dao 3.0
Green dao 3.0
彥彬 洪
 
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp KrennPaintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
JavaDayUA
 
Creating a Facebook Clone - Part XXIV.pdf
Creating a Facebook Clone - Part XXIV.pdfCreating a Facebook Clone - Part XXIV.pdf
Creating a Facebook Clone - Part XXIV.pdf
ShaiAlmog1
 
Creating a Facebook Clone - Part XXXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXXVIII - Transcript.pdfCreating a Facebook Clone - Part XXXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXXVIII - Transcript.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part XI.pdf
Creating an Uber Clone - Part XI.pdfCreating an Uber Clone - Part XI.pdf
Creating an Uber Clone - Part XI.pdf
ShaiAlmog1
 
Creating a Facebook Clone - Part XVIII - Transcript.pdf
Creating a Facebook Clone - Part XVIII - Transcript.pdfCreating a Facebook Clone - Part XVIII - Transcript.pdf
Creating a Facebook Clone - Part XVIII - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdf
ShaiAlmog1
 
Boost Your Development With Proper API Design
Boost Your Development With Proper API DesignBoost Your Development With Proper API Design
Boost Your Development With Proper API Design
MarcusHeld1
 
Creating a Whatsapp Clone - Part XII.pdf
Creating a Whatsapp Clone - Part XII.pdfCreating a Whatsapp Clone - Part XII.pdf
Creating a Whatsapp Clone - Part XII.pdf
ShaiAlmog1
 
Recyclerview in action
Recyclerview in action Recyclerview in action
Recyclerview in action
Pratama Nur Wijaya
 
Creating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdfCreating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdf
ShaiAlmog1
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
Constantine Mars
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
DataArt
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
.NET Conf UY
 
03 Object Relational Mapping
03 Object Relational Mapping03 Object Relational Mapping
03 Object Relational Mapping
Ranjan Kumar
 
Creating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdfCreating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdf
ShaiAlmog1
 
Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpa
Staples
 
Android
AndroidAndroid
Android
ZÅhid IslÅm
 
Creating a Facebook Clone - Part XXIII.pdf
Creating a Facebook Clone - Part XXIII.pdfCreating a Facebook Clone - Part XXIII.pdf
Creating a Facebook Clone - Part XXIII.pdf
ShaiAlmog1
 
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices CrazeKnots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
Alexander Shopov
 

Similar to Creating a Facebook Clone - Part XX - Transcript.pdf (20)

Green dao 3.0
Green dao 3.0Green dao 3.0
Green dao 3.0
 
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp KrennPaintfree Object-Document Mapping for MongoDB by Philipp Krenn
Paintfree Object-Document Mapping for MongoDB by Philipp Krenn
 
Creating a Facebook Clone - Part XXIV.pdf
Creating a Facebook Clone - Part XXIV.pdfCreating a Facebook Clone - Part XXIV.pdf
Creating a Facebook Clone - Part XXIV.pdf
 
Creating a Facebook Clone - Part XXXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXXVIII - Transcript.pdfCreating a Facebook Clone - Part XXXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXXVIII - Transcript.pdf
 
Creating an Uber Clone - Part XI.pdf
Creating an Uber Clone - Part XI.pdfCreating an Uber Clone - Part XI.pdf
Creating an Uber Clone - Part XI.pdf
 
Creating a Facebook Clone - Part XVIII - Transcript.pdf
Creating a Facebook Clone - Part XVIII - Transcript.pdfCreating a Facebook Clone - Part XVIII - Transcript.pdf
Creating a Facebook Clone - Part XVIII - Transcript.pdf
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdf
 
Boost Your Development With Proper API Design
Boost Your Development With Proper API DesignBoost Your Development With Proper API Design
Boost Your Development With Proper API Design
 
Creating a Whatsapp Clone - Part XII.pdf
Creating a Whatsapp Clone - Part XII.pdfCreating a Whatsapp Clone - Part XII.pdf
Creating a Whatsapp Clone - Part XII.pdf
 
Recyclerview in action
Recyclerview in action Recyclerview in action
Recyclerview in action
 
Creating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdfCreating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdf
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
03 Object Relational Mapping
03 Object Relational Mapping03 Object Relational Mapping
03 Object Relational Mapping
 
Creating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdfCreating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdf
 
Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpa
 
Android
AndroidAndroid
Android
 
Creating a Facebook Clone - Part XXIII.pdf
Creating a Facebook Clone - Part XXIII.pdfCreating a Facebook Clone - Part XXIII.pdf
Creating a Facebook Clone - Part XXIII.pdf
 
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices CrazeKnots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
ShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
Jason Yip
 
A Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's ArchitectureA Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's Architecture
ScyllaDB
 
"NATO Hackathon Winner: AI-Powered Drug Search", Taras Kloba
"NATO Hackathon Winner: AI-Powered Drug Search",  Taras Kloba"NATO Hackathon Winner: AI-Powered Drug Search",  Taras Kloba
"NATO Hackathon Winner: AI-Powered Drug Search", Taras Kloba
Fwdays
 
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid ResearchHarnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Neo4j
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
Neo4j
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
Fwdays
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
Ajin Abraham
 
Demystifying Knowledge Management through Storytelling
Demystifying Knowledge Management through StorytellingDemystifying Knowledge Management through Storytelling
Demystifying Knowledge Management through Storytelling
Enterprise Knowledge
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
c5vrf27qcz
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
AlexanderRichford
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
Pablo Gómez Abajo
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
AstuteBusiness
 
AWS Certified Solutions Architect Associate (SAA-C03)
AWS Certified Solutions Architect Associate (SAA-C03)AWS Certified Solutions Architect Associate (SAA-C03)
AWS Certified Solutions Architect Associate (SAA-C03)
HarpalGohil4
 
QA or the Highway - Component Testing: Bridging the gap between frontend appl...
QA or the Highway - Component Testing: Bridging the gap between frontend appl...QA or the Highway - Component Testing: Bridging the gap between frontend appl...
QA or the Highway - Component Testing: Bridging the gap between frontend appl...
zjhamm304
 
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance PanelsNorthern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving
 
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
DanBrown980551
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
Antonios Katsarakis
 
Must Know Postgres Extension for DBA and Developer during Migration
Must Know Postgres Extension for DBA and Developer during MigrationMust Know Postgres Extension for DBA and Developer during Migration
Must Know Postgres Extension for DBA and Developer during Migration
Mydbops
 
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
"Scaling RAG Applications to serve millions of users",  Kevin Goedecke"Scaling RAG Applications to serve millions of users",  Kevin Goedecke
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
Fwdays
 

Recently uploaded (20)

[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
 
A Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's ArchitectureA Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's Architecture
 
"NATO Hackathon Winner: AI-Powered Drug Search", Taras Kloba
"NATO Hackathon Winner: AI-Powered Drug Search",  Taras Kloba"NATO Hackathon Winner: AI-Powered Drug Search",  Taras Kloba
"NATO Hackathon Winner: AI-Powered Drug Search", Taras Kloba
 
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid ResearchHarnessing the Power of NLP and Knowledge Graphs for Opioid Research
Harnessing the Power of NLP and Knowledge Graphs for Opioid Research
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
 
Demystifying Knowledge Management through Storytelling
Demystifying Knowledge Management through StorytellingDemystifying Knowledge Management through Storytelling
Demystifying Knowledge Management through Storytelling
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
QR Secure: A Hybrid Approach Using Machine Learning and Security Validation F...
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
 
AWS Certified Solutions Architect Associate (SAA-C03)
AWS Certified Solutions Architect Associate (SAA-C03)AWS Certified Solutions Architect Associate (SAA-C03)
AWS Certified Solutions Architect Associate (SAA-C03)
 
QA or the Highway - Component Testing: Bridging the gap between frontend appl...
QA or the Highway - Component Testing: Bridging the gap between frontend appl...QA or the Highway - Component Testing: Bridging the gap between frontend appl...
QA or the Highway - Component Testing: Bridging the gap between frontend appl...
 
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance PanelsNorthern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
 
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
LF Energy Webinar: Carbon Data Specifications: Mechanisms to Improve Data Acc...
 
Dandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity serverDandelion Hashtable: beyond billion requests per second on a commodity server
Dandelion Hashtable: beyond billion requests per second on a commodity server
 
Must Know Postgres Extension for DBA and Developer during Migration
Must Know Postgres Extension for DBA and Developer during MigrationMust Know Postgres Extension for DBA and Developer during Migration
Must Know Postgres Extension for DBA and Developer during Migration
 
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
"Scaling RAG Applications to serve millions of users",  Kevin Goedecke"Scaling RAG Applications to serve millions of users",  Kevin Goedecke
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
 

Creating a Facebook Clone - Part XX - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XX Notification is the last client data class that maps to an entity. In that sense it will get more interesting after this point…
  • 2. @Entity public class Notification { @Id private String id; @ManyToOne private User user; private String text; private String reaction; private int reactionColor; private long date; private boolean wasRead; private String postId; private String commentId; public Notification() { id = UUID.randomUUID().toString(); } public NotificationDAO getDAO() { return new NotificationDAO(id, user.getDAO(), text, reaction, reactionColor, date, wasRead, postId, commentId); Notification The class is pretty standard Again these map directly to the client side data
  • 3. @Entity public class Notification { @Id private String id; @ManyToOne private User user; private String text; private String reaction; private int reactionColor; private long date; private boolean wasRead; private String postId; private String commentId; public Notification() { id = UUID.randomUUID().toString(); } public NotificationDAO getDAO() { return new NotificationDAO(id, user.getDAO(), text, reaction, reactionColor, date, wasRead, postId, commentId); Notification A notification might relate to a post or a comment so having its id here might be useful to launch said post when the notification is clicked
  • 4. private long date; private boolean wasRead; private String postId; private String commentId; public Notification() { id = UUID.randomUUID().toString(); } public NotificationDAO getDAO() { return new NotificationDAO(id, user.getDAO(), text, reaction, reactionColor, date, wasRead, postId, commentId); } public String getId() { return id; } public void setId(String id) { this.id = id; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } Notification The constructor and DAO match the convention of the other classes
  • 5. public long getDate() { return date; } public void setDate(long date) { this.date = date; } public boolean isWasRead() { return wasRead; } public void setWasRead(boolean wasRead) { this.wasRead = wasRead; } public String getPostId() { return postId; } public void setPostId(String postId) { this.postId = postId; } public String getCommentId() { return commentId; } public void setCommentId(String commentId) { this.commentId = commentId; } } Notification The rest is again getters & setters
  • 6. public class NotificationDAO { private String id; private UserDAO user; private String text; private String reaction; private int reactionColor; private long date; private boolean wasRead; private String postId; private String commentId; public NotificationDAO() { } public NotificationDAO(String id, UserDAO user, String text, String reaction, int reactionColor, long date, boolean wasRead, String postId, String commentId) { this.id = id; this.user = user; this.text = text; this.reaction = reaction; NotificationDAO The next step is the DAO which again maps very closely. There is literally nothing special here, we might as well have used the Notification entity to some degree.
  • 7. return date; } public void setDate(long date) { this.date = date; } public boolean isWasRead() { return wasRead; } public void setWasRead(boolean wasRead) { this.wasRead = wasRead; } public String getPostId() { return postId; } public void setPostId(String postId) { this.postId = postId; } public String getCommentId() { return commentId; } public void setCommentId(String commentId) { this.commentId = commentId; } } NotificationDAO As you can see the rest of the code is classic boilerplate
  • 8. Newsfeed ✦Why Newsfeed Entity? ✦Consistency ✦Tune Experience © Codename One 2017 all rights reserved This is getting a bit more interesting... Newsfeed represents the feed for a user. I could have just created a really complex join query on Post and called it a day but that's problematic. The newsfeed isn't just a list of posts based on date. It's something that includes a complex algorithm behind it. Running that algorithm every time the user pages through data might be very expensive. Furthermore, changes to the algorithm shouldn't impact past placements. We'd want consistency and we'd also like to have a log of "what did the user see". In that sense constructing the newsfeed as an entity in its own right makes a lot of sense. We can place the articles into the newsfeed using a sort order that makes sense for a specific user without impacting everyone. We can tune and experiment with article placement algorithms easily because our processing can be done offline on the table itself.
  • 9. @Entity public class Newsfeed { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; Newsfeed This is getting a bit more interesting... Newsfeed represents the feed for a user. I could have just created a really complex join query on Post and called it a day but that's problematic. The newsfeed isn't just a list of posts based on date. It's something that includes a complex algorithm behind it. Running that algorithm every time the user pages through data might be very expensive. Furthermore, changes to the algorithm shouldn't impact past placements. We'd want consistency and we'd also like to have a log of "what did the user see". In that sense constructing the newsfeed as an entity in its own right makes a lot of sense. We can place the articles into the newsfeed using a sort order that makes sense for a specific user without impacting everyone. We can tune and experiment with article placement algorithms easily because our processing can be done offline on the table itself. We use an auto-increment numeric id since this object isn't exposed to the client side at any stage the id doesn't matter as much and this id type is faster
  • 10. @Entity public class Newsfeed { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; Newsfeed Every entry within the newsfeed has a user & post. Notice that the user is probably a different user from the one who submitted the post
  • 11. @Entity public class Newsfeed { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; Newsfeed postDay is the number of days since epoch. This is useful for sorting, I want todays posts to always come before yesterdays posts even if they are higher quality
  • 12. @Entity public class Newsfeed { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; Newsfeed Timestamp is also used for the sort but to a lesser degree
  • 13. @Entity public class Newsfeed { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; Newsfeed Rank can be manipulated by a ranking algorithm to push good posts up within the day
  • 14. private User parent; @ManyToOne private Post entry; private long postDay; private long postTimestamp; private int rank; public Newsfeed() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public User getParent() { return parent; } public void setParent(User parent) { this.parent = parent; } public Post getEntry() { return entry; } Newsfeed We have no DAO. We don't need it, this is a server side object
  • 15. return entry; } public void setEntry(Post entry) { this.entry = entry; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } public long getPostDay() { return postDay; } public void setPostDay(long postDay) { this.postDay = postDay; } public long getPostTimestamp() { return postTimestamp; } public void setPostTimestamp(long postTimestamp) { this.postTimestamp = postTimestamp; } } Newsfeed We do need the getters/setters though for the entity
  • 16. public interface NewsfeedRepository extends CrudRepository<Newsfeed, Long>{ @Query("select n from Newsfeed n where n.parent.authtoken = ?1") public Page<Newsfeed> findNewsfeedForUser( String auth, Pageable page); } NewsfeedRepository The Newsfeed also requires a CrudRepository class. We need to use the auth and not the ID to prevent a case where another user gets a peek at my feed which might include "friend only" posts With that we only have one more item...
  • 17. @Entity public class ShadowUser { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String fullName; private String phone; private String email; private String secondaryPhone; @ManyToOne private User owner; public ShadowUser() { } public ShadowUser(ShadowUserDAO dao, User owner) { this.fullName = dao.getFullName(); this.phone = dao.getPhone(); this.email = dao.getEmail(); this.secondaryPhone = dao.getSecondaryPhone(); ShadowUser The shadow user is a "potential" user of whom we have knowledge but he might not be in the social network. Do you ever wonder how Facebook seems to know so much about you before you even signed up? They keep suggesting people that they can't possibly know about... Well, here's one of the tricks they use. When you agree to synchronize your contacts to Facebook (and they nag a lot about this) they upload the whole thing and store it. If you have friends that are already in Facebook you'll get suggestions instantly but they keep everything anyway. When one of your contacts signs up for Facebook they notice that you know and instantly add a suggestion. This works in reverse too, someone has your email or phone number so you'd see them as a suggestion. They go even further by associations e.g. you might have a connection like that through a 3rd party so even if you never synchronized contacts they'd still know. I chose to implement a relatively simple version of this and didn't include all the meta-data that Facebook probably stores. This is mostly a simple proof of concept that should be enough for us to provide friend suggestions. We again use auto-increment for an internal entity
  • 18. @Entity public class ShadowUser { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String fullName; private String phone; private String email; private String secondaryPhone; @ManyToOne private User owner; public ShadowUser() { } public ShadowUser(ShadowUserDAO dao, User owner) { this.fullName = dao.getFullName(); this.phone = dao.getPhone(); this.email = dao.getEmail(); this.secondaryPhone = dao.getSecondaryPhone(); ShadowUser This is the meta-data we gather for a user, there is obviously a lot more we can gather
  • 19. @Entity public class ShadowUser { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String fullName; private String phone; private String email; private String secondaryPhone; @ManyToOne private User owner; public ShadowUser() { } public ShadowUser(ShadowUserDAO dao, User owner) { this.fullName = dao.getFullName(); this.phone = dao.getPhone(); this.email = dao.getEmail(); this.secondaryPhone = dao.getSecondaryPhone(); ShadowUser This is the user who uploaded the data so if the data in this record matches me then I probably know the owner
  • 20. @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String fullName; private String phone; private String email; private String secondaryPhone; @ManyToOne private User owner; public ShadowUser() { } public ShadowUser(ShadowUserDAO dao, User owner) { this.fullName = dao.getFullName(); this.phone = dao.getPhone(); this.email = dao.getEmail(); this.secondaryPhone = dao.getSecondaryPhone(); this.owner = owner; } public Long getId() { return id; } public void setId(Long id) { this.id = id; ShadowUser We have a DAO object but this DAO is write only. So the entity isn't exposed to the outside world but the outside world is exposed to the entity. That’s why we don’t have a getDAO method! We do have a special constructor type that makes adding a new ShadowUser easier.
  • 21. public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getSecondaryPhone() { return secondaryPhone; } public void setSecondaryPhone(String secondaryPhone) { this.secondaryPhone = secondaryPhone; } public User getOwner() { return owner; } public void setOwner(User owner) { this.owner = owner; } } ShadowUser As with the other entities the rest is just setters & getters.
  • 22. public class ShadowUserDAO { private String fullName; private String phone; private String email; private String secondaryPhone; public ShadowUserDAO() { } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; ShadowUserDAO In a sense the ShadowUserDAO is a bit different from the other DAO’s. This is a pretty standard DAO with two big omissions: ID & Owner both of which are missing…
 The ID is redundant as it's auto generated, the owner is also redundant as it's always the user that uploaded the contacts. There is no point of including either one of these values in the DAO as they won't arrive through it from the client.
  • 23. return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getSecondaryPhone() { return secondaryPhone; } public void setSecondaryPhone(String secondaryPhone) { this.secondaryPhone = secondaryPhone; } } ShadowUserDAO The rest of the DAO is just getters and setters
  • 24. public interface ShadowUserRepository extends CrudRepository<ShadowUser, Long> { @Query("select n from ShadowUser n where n.owner.authtoken = ?1") public List<ShadowUser> findShadowUsers(String auth); @Query("select n from ShadowUser n where n.phone = ?1 or " + "n.secondaryPhone = ?1") public List<ShadowUser> findByPhone(String phone); @Query("select n from ShadowUser n where n.email = ?1") public List<ShadowUser> findByEmail(String email); @Query("select count(n) from ShadowUser n where " + "n.owner.authtoken = ?1") public Long countByUser(String auth); @Query("select n from ShadowUser n where n.owner.authtoken = ?1 and " + "n.fullName = ?2") public List<ShadowUser> findByFullName(String auth, String fullName); } ShadowUserRepository In this case the CrudRepository is actually pretty interesting. We need it for the case where we create a new user or update data. We need to find all the related users. Given a users phone we look through the database for users who might have that phone in their contacts, the same is true for email
  • 25. public interface ShadowUserRepository extends CrudRepository<ShadowUser, Long> { @Query("select n from ShadowUser n where n.owner.authtoken = ?1") public List<ShadowUser> findShadowUsers(String auth); @Query("select n from ShadowUser n where n.phone = ?1 or " + "n.secondaryPhone = ?1") public List<ShadowUser> findByPhone(String phone); @Query("select n from ShadowUser n where n.email = ?1") public List<ShadowUser> findByEmail(String email); @Query("select count(n) from ShadowUser n where " + "n.owner.authtoken = ?1") public Long countByUser(String auth); @Query("select n from ShadowUser n where n.owner.authtoken = ?1 and " + "n.fullName = ?2") public List<ShadowUser> findByFullName(String auth, String fullName); } ShadowUserRepository We check if a user has uploaded contacts in the past by counting his entries, assuming he has we will try to merge the data
  • 26. public interface ShadowUserRepository extends CrudRepository<ShadowUser, Long> { @Query("select n from ShadowUser n where n.owner.authtoken = ?1") public List<ShadowUser> findShadowUsers(String auth); @Query("select n from ShadowUser n where n.phone = ?1 or " + "n.secondaryPhone = ?1") public List<ShadowUser> findByPhone(String phone); @Query("select n from ShadowUser n where n.email = ?1") public List<ShadowUser> findByEmail(String email); @Query("select count(n) from ShadowUser n where " + "n.owner.authtoken = ?1") public Long countByUser(String auth); @Query("select n from ShadowUser n where n.owner.authtoken = ?1 and " + "n.fullName = ?2") public List<ShadowUser> findByFullName(String auth, String fullName); } ShadowUserRepository We use the full name of the user when merging contact data. With that we finished all the entities and we are finally ready to move up the food chain to the service layer!