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

Architecting the Redbooth Android App - GDG Barcelona Android Community Day

Architecting the Redbooth Android App - GDG Barcelona Android Community Day

In this talk we presented the way we develop features at the Redbooth Android Team, and how we create the different components following our architecture.

Rubén Serrano

February 25, 2017
Tweet

More Decks by Rubén Serrano

Other Decks in Technology

Transcript

  1. ▸ The user can enter a rating (from 1 to

    5) or decide to not rate ▸ If there’s a rating and it’s a 5, we want to thank him and ask for a marketplace rating ▸ If there’s a rating and it’s <5, we want to tell him if he wants to contact with support ▸ In any case, we want to store the rating (or decision to not rate) for a later use ARCHITECTING THE ANDROID APP EXAMPLE USE CASE: RATE
  2. public class Rating {
 private RatingStatus status;
 private int value;


    // Other constants, getters, constructors, builders... 
 public boolean isPromoter() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isPromoter = value >= PROMOTER_RATING;
 return hasBeenEvaluated && isPromoter;
 }
 
 public boolean isDetractor() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isDetractor = value < PROMOTER_RATING;
 return hasBeenEvaluated && isDetractor;
 }
 
 public boolean hasBeenRated() {
 return status != RatingStatus.NOT_RATED;
 }
 }
  3. public class Rating {
 private RatingStatus status;
 private int value;


    // Other constants, getters, constructors, builders... 
 public boolean isPromoter() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isPromoter = value >= PROMOTER_RATING;
 return hasBeenEvaluated && isPromoter;
 }
 
 public boolean isDetractor() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isDetractor = value < PROMOTER_RATING;
 return hasBeenEvaluated && isDetractor;
 }
 
 public boolean hasBeenRated() {
 return status != RatingStatus.NOT_RATED;
 }
 }
  4. public class Rating {
 private RatingStatus status;
 private int value;


    // Other constants, getters, constructors, builders... 
 public boolean isPromoter() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isPromoter = value >= PROMOTER_RATING;
 return hasBeenEvaluated && isPromoter;
 }
 
 public boolean isDetractor() {
 boolean hasBeenEvaluated = status == RatingStatus.EVALUATED;
 boolean isDetractor = value < PROMOTER_RATING;
 return hasBeenEvaluated && isDetractor;
 }
 
 public boolean hasBeenRated() {
 return status != RatingStatus.NOT_RATED;
 }
 }
  5. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 } 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.isPromoter()) {
 notifyPromoter();
 } else if (rating.isDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  6. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 }
 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.isPromoter()) {
 notifyPromoter();
 } else if (rating.isDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  7. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 }
 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.isPromoter()) {
 notifyPromoter();
 } else if (rating.isDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  8. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 }
 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.isPromoter()) {
 notifyPromoter();
 } else if (rating.isDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  9. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 }
 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.getRatingStatus() != RatingStatus.EVALUATED && rating.getValue >= PROMOTER_RATING) {
 notifyPromoter();
 } else if (rating.isDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  10. public class RateUseCase implements Runnable {
 private RatingStorage storage;
 //...

    @Inject
 RateUseCase(RatingStorage storage) {
 this.storage = storage;
 }
 
 public void execute(Rating rating) {
 storage.storeRating(rating);
 if (rating.isPromoter()) {
 notifyPromoter();
 } else if (rating.sDetractor()) {
 notifyDetractor();
 }
 } //...
 }
  11. ▸ […] This rule says that source code dependencies can

    only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle […] ▸ […] the further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies. ▸ From The Clean Architecture by Robert C. Martin ARCHITECTING THE ANDROID APP THE DEPENDENCY RULE
  12. public class DashboardPresenter {
 private final RateUseCase rateUseCase;
 private final

    DashboardActivity activity;
 
 @Inject
 DashboardPresenter(DashboardActivity activity,
 RateUseCase rateUseCase) {
 this.activity = activity;
 this.rateUseCase = rateUseCase;
 }
 
 void rate(Rating rating) {
 rateUseCase.execute(rating, new RateUseCase.Callback() {
 @Override
 public void notifyDetractor() {
 activity.showDetractorDialog();
 }
 
 @Override
 public void notifyPromoter() {
 activity.showPromoterDialog();
 }
 });
 }
 }
  13. public class RatingStorage {
 private final SharedPreferences preferences;
 // ...

    
 @Override
 public void storeRating(Rating rating) {
 SharedPreferences.Editor editor = preferences.edit();
 editor.putInt(KEY_RATING_STATUS_VALUE, rating.getRatingStatusValue());
 editor.putInt(KEY_RATING_VALUE, rating.getRatingValue());
 editor.apply();
 }
 }
  14. ▸ When the output or status change is produced combining

    the input and the status of the object ▸ When the output or status change is produced directly from the status of the object ▸ When the output or status change is produced directly from the input ARCHITECTING THE ANDROID APP WHEN TO UNIT TEST
  15. Q&A