Plugin-User-Behavior-Collection
Background
The more we know about our users, the better equipped we'll be to make smart choices about our application development investments. It is the truth not only for re-search but also for each Carina studio. However, the problem is how to design a common solution which could be applied to every studio without modifying their own business code. The most intuitive way is to use declarative programming, which could decouple the tracking tools from any business logics.
Design ideas
- There is one common metric for event tracking, while every studio could have their own standard metrics. (Of course, the standard metric could be flexibly expanded)
// common metric
// A config file to determine which method belongs to the method in the common metric ;
// A file to combine the common metric and the defined standard methric ;; ;;Object.keysmethodName.forEachresult = definedWatchList;// You can put your own defined tracking method here;
- Given that each user behavior will trigger any corresponding callback function, we could track these functions.
Until now, I have two ways. Firstly, for those functions that meet the following requirements: the function must be defined with a function name and must not be called as an arrow function:
// This is a valid callback function { console; } { return <button onClick=thishandleButtonAClick>buttonA</button> }// The followings are invalid callback functions { console; } { return <button onClick=thishandleButtonAClick>buttonA</button> } // Or { return <button onClick={ console }>buttonA</button> }
User could simply add a decorator at the top of the class (shown below):
@Component ...
Secondly, for others, users also need to add decorator at the top of each method, and wrapper the class with my given tracking method (shown below):
@Component @ { console; thispropshistory; }; const TrackedApp = App;
-
Event tracking functions will be called after any callback function, and they could not change any data/return result in business logic code.
-
Since we need to decouple this event tracking tool from any business logic code, I prefer using HOC (higher-order component) or decorator, so that we only need to package the tracking tool as a plugin/library, and import it in each component file.
-
User do not need to send the collected data manually.
-
Support to send several tracking events after one user behavior.
For 5 and 6, considering sending too many HTTP requests will slow the render speed, it may be better to pile up the data collected from several tracking events, and send them once together. Till now, my design is to send a HTTP request at the end of each session. I will use a sessionStorage to temporarily store the behaviors triggered during this session. e.g. -
For each session (user opens a page until closing it), a uid will be automatically generated. All triggered behaviros during this session will share this uid.
-
Each behavior triggered by user will also trigger other render functions (e.g. componentDidMount). These behaviors could be regarded as one event, and they share one event ID.
-
I also design a ticker to count the page's dwell time (It is not enough if we only record the trigger time of each behavior because user may temporarily minimize the browser window or change to other browser tabs).
-
For re-search, we also want to have the search content when collecting the user behavior info of 'clicking any search result' event. The most straightforward is to capture the value of the searchbox element. Therefore, we store the unique id of the searchbox element as a global variable, and fetch the search content using
searchContent: SEARCHBOX_ID !== '' ? HTMLInputElementdocument.getElementByIdSEARCHBOX_ID.value : 'Not applicable',
- For re-search, we also want to know the sequence number of the clicked result among all the returned results. It is not good enough if we pass the BE data to the user behavior collection part. So, we still use DOM to do that. A global variable 'SEARCHBOX_LAYER' needs to be set. This variable defines whether the clicked element is at outermost layer. For example:
我的附件测试 http://itsptest.orientsec.com.cn:8001/upload/IMG_S_20191111173025600.jpeg 啊啊啊
when you click the element
我的附件测试
It is not at the outermost layer, while its parent node is. Therefore, SEARCHBOX_LAYER is set to be 1. After we get the outermost node of the clicked element, we use the following mehtod to get the sequence number:
position: SEARCHRESULT_LAYER !== "" ? Array.prototype.indexOf.call_.getnode, "parentNode.children", , node + 1 : "Not applicable";
Install
npm i plugin-user-behavior-collection
Usage
- Add user info and ticker
UserInfo userName="Serina" / RunTicker /
- For methods that could be found using Object.prototype.hasOwnProperty (which is not defined with arrow function):
Add a config file ('methodName.ts') to determine which method belongs to the method in the common metric
;
Add another file ('defined-behaviors.ts') to combine the common metric and the defined standard methric
;; ;;Object.keysmethodName.forEachresult = definedWatchList;// You can put your own defined tracking method here;
Import these methods to every class
;
- For methods that could not be found using Object.prototype.hasOwnProperty (which is defined with arrow function):
Bind the tracking method with the specific method separately.
Example
You can see an example under 'example' folder, by using:
cd examplenpm installnpm run start