Slide 1

Slide 1 text

Design patterns Ben

Slide 2

Slide 2 text

What I did..

Slide 3

Slide 3 text

Refactoring

Slide 4

Slide 4 text

Simple design patterns

Slide 5

Slide 5 text

Singleton pattern When to Use Singleton pattern should be used when we must ensure that only one instance of a class is created and when the instance must be available through all the code. A special care should be taken in multi-threading environments when multiple threads must access the same resources through the same singleton object. Common Usage ● Logger Classes ● Configuration Classes ● Accessing resources in shared mode ● Other design patterns implemented as Singletons: Factories and Abstract Factories, Builder, Prototype

Slide 6

Slide 6 text

Singleton pattern Buzzscreen go - Mysql Lazy loading ● Early vs Lazy Keep in mind ● Synchronized ● Initialize members when the instance is initialized ● Most members shouldn’t have a state ● Shouldn’t pass a parameter can have a state (like context) func getEsInstance() *SingletonElasticsearch { onceElasticsearch.Do(func() { instanceElasticsearch = &SingletonElasticsearch{} core.Logger.Infof("getEsInstance() - %s", Config.ElasticSearch.Host) var err error logger := ElasticInfoLogger{} httpClient := &http.Client{ Timeout: time.Second * 3, } optionsFuncs := []elastic.ClientOptionFunc{ elastic.SetURL(Config.ElasticSearch.Host), elastic.SetHealthcheckTimeout(10 * time.Second), elastic.SetSniff(false), elastic.SetErrorLog(logger), elastic.SetHttpClient(httpClient), } instanceElasticsearch.Elasticsearch, err = elastic.NewClient(optionsFuncs...) ... }) return instanceElasticsearch }

Slide 7

Slide 7 text

Factory pattern When to Use Factory pattern should be used when: ● a framework delegate the creation of objects derived from a common superclass to the factory ● we need flexibility in adding new types of objects that must be created by the class Common Usage Along with singleton pattern the factory is one of the most used patterns. Almost any application has some factories. Here are a some examples in java: ● factories providing an xml parser: javax.xml.parsers.DocumentBuilderFactory or javax.xml.parsers.SAXParserFactory ● java.net.URLConnection - allows users to decide which protocol to use

Slide 8

Slide 8 text

Factory pattern Buzzscreen core - Campaign presenter Keep in mind ● Return type can be a super class or an interface ● Don’t pass an argument which is related to return type ● If possible, define the presenter constructor as protected or default - Why? public class CampaignPresenterFactory { public static CampaignPresenter getPresenter(Context context, Campaign campaign) throws UnsupportedCampaignException { CampaignPresenter presenter; switch (campaign.getCreative().getType()) { default: case IMAGE: presenter = new NativeCampaignPresenter(context, campaign, true); break; case NATIVE: presenter = new NativeCampaignPresenter(context, campaign); break; case SDK: presenter = new SdkCampaignPresenter(context, campaign); break; case WEB: case JS: presenter = new WebCampaignPresenter(context, campaign); break; } return presenter; } }

Slide 9

Slide 9 text

Builder pattern When to Use Builder pattern should be used when: ● the creation algorithm of a complex object is independent from the parts that actually compose the object ● the system needs to allow different representations for the objects that are being built Example ● Java ○ CaptchaResult.java ○ Usage ● Go ○ EsQueryBuilder.go ○ Usage

Slide 10

Slide 10 text

Builder pattern Buzzscreen core - HttpRequest Keep in mind ● Members shouldn’t be public ● Don’t provide setter method in the main class ● Return builder itself in order to be a chain public class HttpRequest { private static final String TAG = HttpRequest.class.getSimpleName(); @Expose protected String url; protected String waitString; … protected HttpRequest(Context context) { this.context = context; } public static class Builder { protected HttpRequest httpTask; public Builder(Context context) { httpTask = new HttpRequest(context); if (queue == null) { queue = Volley.newRequestQueue(context); queue.start(); } } public Builder addParam(String key, Object value) { httpTask.params.put(key, String.valueOf(value)); return this; } public Builder setUrl(String url) { httpTask.url = url; return this; } public HttpRequest build() { return httpTask; } } }

Slide 11

Slide 11 text

Observer pattern When to Use The observer pattern is used when: ● the change of a state in one object must be reflected in another object without keeping the objects tight coupled. ● the framework we are writing needs to be enhanced in future with new observers with minimal changes. Common Usage ● Model View Controller Pattern - The observer pattern is used in the model view controller (MVC) architectural pattern. In MVC the this pattern is used to decouple the model from the view. View represents the Observer and the model is the Observable object. ● Event management - This is one of the domains where the Observer patterns is extensively used. Swing and .Net are extensively using the Observer pattern for implementing the events mechanism.

Slide 12

Slide 12 text

Observer pattern https://stackoverflow.com/questions/ 33486006/should-we-use-weakreferen ce-in-observer-pattern Keep in mind ● Use WeakReference if possible ● I think map is better than list for observer holders ● Always keep in mind that you should write an unregister code right after when you write a register code

Slide 13

Slide 13 text

Adapter pattern When to Use The visitor pattern is used when: ● When you have a class(Target) that invokes methods defined in an interface and you have a another class(Adapter) that doesn't implement the interface but implements the operations that should be invoked from the first class through the interface. You can change none of the existing code. The adapter will implement the interface and will be the bridge between the 2 classes. ● When you write a class (Target) for a generic use relying on some general interfaces and you have some implemented classes, not implementing the interface, that needs to be invoked by the Target class. Common Usage ● Non Software Examples of Adapter Patterns : Power Supply Adapters, card readers and adapters, ... ● Software Examples of Adapter Patterns: Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.

Slide 14

Slide 14 text

Adapter pattern https://github.com/Buzzvil/slidejoy-android/bl ob/63265157d3458b35ce3320c1d366994f7f9 3edc7/app/src/main/java/com/slidejoy/contr ol/HeaderRecyclerAdapter.java#L11 Keep in mind ● Consider any target class can work with your adapter public abstract class HeaderRecyclerAdapter extends RecyclerView.Adapter { protected static final int TYPE_HEADER = -2; protected static final int TYPE_ITEM = -1; RecyclerHeader recyclerHeader; public void setRecyclerHeader(RecyclerHeader recyclerHeader) { this.recyclerHeader = recyclerHeader; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder viewHolder; if (isHeaderType(viewType)) { viewHolder = recyclerHeader.onCreateHeaderHolder(parent, viewType); } else { viewHolder = onCreateItemHolder(parent, viewType); } return viewHolder; } protected abstract int getCount(); protected abstract VH onCreateItemHolder(ViewGroup parent, int viewType); protected abstract void onBindItemHolder(VH holder, int position); public interface RecyclerHeader { H onCreateHeaderHolder(ViewGroup parent, int viewType); void onBindHeaderHolder(H holder, int position); } }

Slide 15

Slide 15 text

Project design patterns

Slide 16

Slide 16 text

MVC pattern (Buzzscreen go) Model ● Data used by business logic ● DAO - DBMS related ● Light model is preferred View ● Presentation logic Controller ● Select a business logic to process data ● Return the result to the view

Slide 17

Slide 17 text

MVC - Model https://github.com/Buzzvil/slidejoy-appserver /blob/master/src/main/java/com/slidejoy/ser ver/model/UserTransaction.java Keep in mind ● DON’T include any business logic ● SHOULDN’T import controller or service packages (package level cycling dependency) @Entity @Table(name = "tbl_userTransactionBS") @Accessors(chain = true) @ToString public class UserTransaction { public enum Status { Withdraw(1), Submit(2), Issue(3), Fail(4), Refund(5), Cancel(6); final int num; Status(int num) { this.num = num; } public int get() { return num; } } @Id @GeneratedValue(strategy = GenerationType.AUTO) @Getter long transactionId; @Getter @Setter String userId, account, storeName, productName, note; @Getter @Setter int productId, carats, status, orderId; }

Slide 18

Slide 18 text

MVC - DTO https://github.com/Buzzvil/buzzscreen/blob/d 177d430e30aafbd42e7ce0c1205c84ff0496c2 8/buzzscreen-api/buzzscreen/dto/allocation_ v1.go Keep in mind ● Data transfer object also doesn’t have any business logic ● Model classes shouldn’t import dto classes ● DTO & Model ○ Inheritance.. package dto type ( AllocV1Request struct { ContentAllocV1Request IsTest bool `form:"is_test"` UserAgentReq string `form:"user_agent"` SettingsPageDisplayRatio string `form:"settings_page_display_ratio"` DefaultBrowser string `form:"default_browser"` InstalledBrowsers string `form:"installed_browsers"` IsIfaLimitAdTrackingEnabled bool `form:"is_ifa_limit_ad_tracking_enabled"` userAgent string } AllocV1Settings struct { AdFilteringWords *string `json:"ad_filtering_words"` BaseHourLimit int `json:"base_hour_limit"` BaseInitPeriod int `json:"base_init_period"` ExternalBaseReward int `json:"external_base_reward"` ... } )

Slide 19

Slide 19 text

MVC - Controller Keep in mind ● If there is a logic doesn’t strongly related with API, you should consider to implement the logic in service layer. Unless, you will have a moster controller. (And you might have many duplicated or similar code) buzzscreen/controller/device_v1.go func InitDeviceV1(c *gin.Context) { var deviceReq dto.InitDeviceV1Request err := bindValue(c, &deviceReq) ... device, _ := service.HandleNewDevice(&requestedDevice, c.Request) ... writeJsonSafely(c, http.StatusOK, res) } buzzscreen/controller/device.go func PostDevice(c *gin.Context) { var deviceReq dto.DeviceRequest err := bindValue(c, &deviceReq) ... device, isNewDevice := service.HandleNewDevice(&requestedDevice, c.Request) ... writeJsonSafely(c, http.StatusOK, res) }

Slide 20

Slide 20 text

MVC - Service https://github.com/Buzzvil/slidejoy-appserver/blob /935cc0288ec34be92fd319ac9bcb71f9bc9e7900/s rc/main/java/com/slidejoy/server/service/StoreSer vice.java Controller vs Service If we are running a restaurant.. ● Controller - Serving food ● Service - Kitchen @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") @Service public class StoreService { @Autowired private UserTransactionDao userTransactionDao; @Autowired private UserBalanceDao userBalanceDao; @Autowired private AbuserService abuserService; @Transactional public UserTransaction buyProduct(String userId, Product product, String account) { if (abuserService.isAbuser(userId, account) == true) { return null; } final UserBalance balance = userBalanceDao.getByUserId(userId); final int caratPrice = product.getPrice(); if (balance.getCurrentBalance() > caratPrice) { userBalanceDao.save(balance.addBalance(0 - caratPrice)); UserTransaction userTransaction = new UserTransaction().setUserId(userId).setCarats(caratPrice).setProductId(product.getProductId()) … userTransaction = userTransactionDao.save(userTransaction); return userTransaction; } return null; } }

Slide 21

Slide 21 text

MVC - DAO All you have to do is extends CrudRepository interface. Spring framework will take care the others. // slidejoy/server/model/UserTransactionDao.java package com.slidejoy.server.model; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface UserTransactionDao extends CrudRepository { UserTransaction getByTransactionId(long transactionId); UserTransaction getByTransactionIdAndOrderId(long transactionId, int orderId); List getByUserId(String userId); } // slidejoy/server/model/UserBalanceDao.java public interface UserBalanceDao extends CrudRepository { UserBalance getByUserId(String userId); }

Slide 22

Slide 22 text

MVP pattern Presenter ● View 1 <-> 1 Presenter ○ Lifecycle perspective ○ Don’t pass presenter to singleton instance like manager.. ● View doesn’t have any reference of presenter ○ Because you can define different presenters for different models for same view ● Event start from View? ○ Easy to implement (As you can see...) ● Events starts from Model? ○ I recommend to follow observer pattern

Slide 23

Slide 23 text

MVP - Presenter Keep in mind ● Don’t import Presenter in View or Model ● Before write a code in presenter, think one more whether it can be done in view or model layer. It will keep the presenter tidy and prevent view and model from becoming empty ● What can we do with a monster presenter? public class TicTacToePresenter implements Board.EventListener, TicTacToeView.EventListener { private TicTacToeView view; private Board model; // Define event listeners here. You can still write a view structure related code in View classes. But all logics of view should be here. public TicTacToePresenter(TicTacToeView view) { this.view = view; this.model = new Board(); this.model.addEventListener(this); } @Override public void finalize() { // This is optional this.model.removeEventListener(this); } @Override public void onBoardChanged(Board model) { // Update view } // When the user selects a cell, our presenter only hears about what was (row, col) pressed, it's up to the view now to determine that from the Button that was pressed. @Override public void onButtonSelected(int row, int col) { Player playerThatMoved = model.mark(row, col); if(playerThatMoved != null) { view.setButtonText(row, col, playerThatMoved.toString()); if (model.getWinner() != null) { view.showWinner(playerThatMoved.toString()); } } } }

Slide 24

Slide 24 text

MVP - Model Keep in mind ● Model’s eventListener members should be a WeakReferenceMap ○ Otherwise, you will have a memory leak public class Board { WeakReferenceMap listeners = new WeakReferenceMap<> public void addListener(EventListener listener) { if (listeners.contains(listener) == false) { listeners.put(listener, listener); } } public void removeListener(EventListener listener) { if (listeners.contains(listener)) { listeners.remove(listener); } } … }

Slide 25

Slide 25 text

Other rules

Slide 26

Slide 26 text

Other rules ● Try not to make a circular dependency ○ There should be a way to prevent it. If it is not? let’s find what make it impossible and refactor it. ● How to manage packages? ○ Package by component - Activity / Service / EventReceiver ... ○ Package by feature - Feed / Store / Ad / Content … ○ Package by feature is preferred

Slide 27

Slide 27 text

Other rules ● Don’t make a function with more than 50 lines. ○ A function should be shown without a scroll. ○ Don’t make a class with more than 1000 lines. ○ The function name should represent all work done inside the function. ● Don’t use static keyword w/o final ○ Why? It is hard to follow where to initialize or update the field (ServerConfig.java) ○ All static field w/o final can be written in Singleton design pattern ● Think one more before creating xxManager and xxUtils ○ Controller & Manager & Handler

Slide 28

Slide 28 text

Let’s make rules together

Slide 29

Slide 29 text

Q & A