決定搬家到點部落
並且把 Blog 命名為 : 技術債
因為目前最為討厭的事情就是處理技術債
但是該還的總有一天會還
不如就把當初留的債都記錄下來吧
Technical debt
2016年5月15日 星期日
2015年11月22日 星期日
電商大講堂 - 心得
為期 2 天由資策會主辦的講座,
各種辛酸血淚的分享與行銷經驗,
此文無法道盡 8 個講堂。
依自己的印象及紀錄日後能繼續深究的工具及知識,
如果有些實際/實務經驗更能與講師產生共鳴。
各種辛酸血淚的分享與行銷經驗,
此文無法道盡 8 個講堂。
依自己的印象及紀錄日後能繼續深究的工具及知識,
如果有些實際/實務經驗更能與講師產生共鳴。
講堂1 -- 電商的行銷預算配置
- 指名度非常重要,In Taiwan 想到網購就想到 PChome Yahoo...
- 搞懂你產品 ( 想要 ? 需要 ? )與客群
- 虛擬通路與實體通路不應該是 1 + 1 = 2
- 部落客推薦 - 意象傳遞
講堂2 -- 在精準度、價格與搜尋量三難中取得 Google Adwords 最佳解
- 在關鍵字的策略避開廣義
- 了解客戶情境與需求
- 網友使用搜尋的習慣
- 出價策略上調整,千萬別用金錢去換跳出率只會把 SEO 越搞越爛
- Google Trends 搜尋趨勢
- Using Dynamic Search Ads
講堂3 -- 行動流量的實戰經驗
- 不要一開始強迫別人來註冊你家會員
- 購買步驟少一步是一步
- 打字不如選,選不如不用選
- 中途放棄購物提供加入收藏功能
- 購買後 Hot sales & Also buy
- 公司預算夠的話還是建議開發 Native APP for mobile
講堂4 -- 電商平台在 Facebook 廣告投放下的轉換率解析
- 50%技術 + 50 %策略才能成就好的紛絲團經營
- 粉絲團經營的不是粉絲而是粉絲的朋友 (觸及)
- 質重於量
- 廣告投射善用 Tools 過濾忠實粉絲 / 消費過對象
- Data & Analytics
- Facebook Pixel
- Website Custom Audiences
- Facebook 動態產品廣告
- 出價策略之後都會採用 OCPM
- Growth Hack (這裡找到 Xdite 分享的一篇初級入門文 )
講堂5 -- 讓電商諸葛亮,做你的跨境軍師
- 進入市場的事前功課分析不可少
講堂6 -- 流量的品質與轉換率指標
- 終極目標就是將潛在客戶轉換為忠實客戶
- 廣告預算的取捨
- 流量大 != 成交量大
- 收集各種成交 data 客戶群組合
- 細水長流的穩健發展才是最真實的
講堂7 -- 創造顧客終身價值的第一步:edm
- 主打忠實訂閱客戶
- 禁止買名單、濫發
- 垃圾郵件的象徵與 ISP 扣分機制
- 經營自家的 Mail Server 分數
- EDM 發送時段
講堂8 -- 電商平台跨媒體投放轉換率解析
- Google Analytics 網站分析資訊網
- 為廣告網址產生自訂廣告活動參數
- 別為一時的流量產生過多的情緒
- 從數據的分析解讀頁面缺失
- 文案數據分析與工程師的配合缺一不可
2015年5月31日 星期日
自動測試與 TDD 實務開發第三梯 - 心得後記
去年因為 Cash & Raymond 有幸參加第二梯,
但是基本功 & 物件導向觀念還太菜的我,一直很難跟上進度。
今年初看到 SkillTree 開出第三梯課程,就趕緊湊人報名。
一樣是連續 3 周 7 個小時拳拳到肉的觀念與實作的課程 By Joey。
「那不是應該 QA 負責的嗎?為什麼要由 Developer 寫?」
「聽起來很棒!但是並不適合我們公司文化。」
「應該不是我的 Bug 吧?我在我電腦 Rnu 過都是沒問題的阿…」
「我猜 Bug 可能是這段 Code 的關係…」
相信上述對話都真實發生過,
上過這個課程後會對這些疑問及觀念有極大的收穫。
Day 1
- 3A 原則 - Arrange, Act, Assert
- Unit Test 特性 - FIRST
- 測試框架 MsTest
- 3 種驗證方式 - 回傳值/狀態改變/外部互動
- 物件導向 - 相依/隔離
- 手刻 Stub
- Stub/Mock Framework - NSubstitute
- Internal Testing
- Code Coverage
- Web Testing - Selenium IDE
- FluentAutomation
- MessageHangler Unit Test
- Contorller Unit Test
- Page Object Pattern by FluentAutomation
- Refactoring
- TDD
- BDD by Cucumber
- Specflow
- ATDD
- Auto Generate Document
- how to PO/PM/SA support you ?
- CI introduction
講師真的很專業也很熱心,
都能給予一些實務開發上的建議與不同的想法。
也很感謝該單位提供這麼物超所值的課程阿!
最後這堂課程給我感觸最深的一段話︰
友善連結︰
2015年4月20日 星期一
JavaScript 網頁應用程式設計 閱讀後記
函式庫 Spine、Backbone、JavaScriptMVC 這 3 個章節因為沒有使用就跳過沒看了。
如果日後有需要再去翻閱即可。
這本主要是要講解 MVC 架構在 JavaScript 上的實現及觀念。
jQuery Framework 還是非常強大,
書中範例解釋許多 jQuery API 還蠻詳盡的,
以及如何使用這些工具打造基本的 MVC 架構。
循序漸進的方式改良程式碼及解耦合。
而且讀到訂閱模式跟代理器又跟前幾周學的 Flux 架構有連結到,
當然這本書出版有段時間了,
裡面舉例的有些 Library 放到現代來看就沒這麼普遍。
但許多觀念我覺的有紮實的學到,
對於日後有助於在撰寫程式碼或思考上都會有所幫助。
2015年3月29日 星期日
FLUX 架構 - 使用原生 JavaScript
隨著 ReactJS 的火紅,
另一項被大家所期待的就是 Flux ,
官方也特此開了一個站點去詳細介紹這個資料流概念,
各位點進去就會看到下面這張圖片。
第一次我聽完 小翊 介紹完 Flux 與 ReFlux ( 國外某人把 Flux 簡化後推出的 Lib)
完全是空有概念很難想像實際要寫的時候該如何實作。
今天就是給各位展示如何使用 JavaScript,
然後完全不用任何 Framework 去展現 Flux 架構與精神。
首先,要來定義 Flux 架構。
大家可觀察到扣除 Render 後其實跟官方的圖片其實就差不多一致了。
由於 Render 的工作內容已由 ReactJS 取代掉了,
所以 Flux 資料流中並沒有出現這個角色在。
今天要展示的 JavaScript 需求如下︰
看到這可能一堆人會說「根本是在汙辱我」、「很簡單啊」
舉 jQuery 來說好了,
來個監聽 input keyup 事件就搞定了。
但篇幅就是要來介紹如何不使用 Framework 並且套入 Flux 架構去完成。
而不是用各位熟悉的框架去達到此目的。
先定好下方的 HTML。
一般如果要監聽會經常看到以下這樣寫︰
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', function(){
//do something...
});
this.inputBox.addEventListener('keyup', function(){
//do something...
});
}
};
如果想要把 function 獨立出來可以這樣變化︰
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this.clcik1);
this.inputBox.addEventListener('keyup', this.keyup1);
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
如果再 click1 跟 keyup1 中想使用 dispatcher 的變數或方法︰
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this.clcik1.bind(this));
this.inputBox.addEventListener('keyup', this.keyup1.bind(this));
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
到目前為止大家應該都能接受,
如果要切的乾淨就再把 function 切出去。
但是重新檢視一下我們的 Flux 視圖,
我們應該要把元素跟事件分離乾淨,
所以需要把事件註冊到統一的分配器,
再針對不同的事件做處理,
這時候我們就可以用到 JavaScript 內建的 handEvent 了。
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this);
this.inputBox.addEventListener('keyup', this);
},
handleEvent: function(e){
switch(e.type){
case 'click':
switch(e.target){
case this.displayBlock:
this.click1();
break;
}
break;
case 'keyup':
switch(e.target){
case this.inputBox:
this.keyup1();
break;
}
break;
}
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
這樣就完成了呼叫的統一了,
而且也不用寫 bind(this) 就能呼叫到 dispatcher 內的變數與方法。
如果需要反註冊的話可以使用︰
this.displayBlock.removeEventListener('click', this);
為了將資料處理分離,我們需要一個 Store (資料處理器) 來負責處理,
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
getSomething: function (){
return this._data;
},
setSomething: function (val) {
this._data = val;
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//click 事件在此需求無需關注
//this.displayBlock.addEventListener('click', this);
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
}
//略
};
資料分配器 Store 應該避免掉從外部直接改變
可以在呼叫端使用 window.DispatchEvent 發送自訂事件 CustomerEvent ,
並在 Store 內接收自訂事件去做到。
所以在觸發行為時也不會去撰寫 Store.doSomething()
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
init: function(){
window.addEventListener('store_set',this);
},
handleEvent: function (val) {
switch(e.type){
case 'store_set':
this.setSomething(e.detail.val);
break;
}
},
getSomething: function (){
return this._data;
},
setSomething: function (val) {
this._data = val;
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
this.store.init();
},
handleEvent: function(e){
switch(e.type){
/*
case 'click':
switch(e.target){
case this.displayBlock:
this.click1();
break;
}
break;
*/
case 'keyup':
switch(e.target){
case this.inputBox:
//觸發自訂事件
window.dispatchEvent(new CustomEvent('store_set',
{'detail':{'val':this.inputBox.value}}
));
break;
}
break;
}
}
// click1() & keyup1() 這2個假事件可以拿掉無需關注
};
最後來做出 Render 來改變畫面,
透過 Store 發送通知 Render 來繪製。
Render.js
var Render = {
init: function(element, Store){
this.element = element;
this.store = Store;
window.addEventListener('render_view', this);
},
handleEvent: function(e){
switch(e.type){
case 'render_view':
this.element.textContent = this.store.getSomething();
break;
}
}
};
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
init: function(){
window.addEventListener('store_set',this);
},
handleEvent: function(e){
switch(e.type){
case 'store_set':
this.setSomething(e.detail.val);
break;
}
},
getSomething: function () {
return this._data;
},
setSomething: function (val) {
this._data = val;
window.dispatchEvent(new CustomEvent('render_view'));
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
this.store.init();
Render.init(this.displayBlock, this.store);
},
handleEvent: function(e){
switch(e.type){
case 'keyup':
switch(e.target){
case this.inputBox:
//觸發自訂事件
window.dispatchEvent(new CustomEvent('store_set',
{'detail':{'val':this.inputBox.value}}
));
break;
}
break;
}
}
};
Dispatcher.init();
所以上述程式碼實現︰
由 Dispatch 註冊 Render,並傳入 Store 與所需的 View 元件,
資料更新完全由 Store 控制,
Render 去渲染 View 元件。
透過大量的 handleEvent 降低邏輯,資料,與介面元件之間的關聯程度。
之後再去研究 Flux 與 ReFlux 應該也比較好上手。
以上程式範例參照 Gasolin 發表的一篇漸進改善程式碼的組織方式的文章加以修改。
友善連結︰
另一項被大家所期待的就是 Flux ,
官方也特此開了一個站點去詳細介紹這個資料流概念,
各位點進去就會看到下面這張圖片。
擷取自 ReactJS 官方網站 |
第一次我聽完 小翊 介紹完 Flux 與 ReFlux ( 國外某人把 Flux 簡化後推出的 Lib)
完全是空有概念很難想像實際要寫的時候該如何實作。
今天就是給各位展示如何使用 JavaScript,
然後完全不用任何 Framework 去展現 Flux 架構與精神。
首先,要來定義 Flux 架構。
大家可觀察到扣除 Render 後其實跟官方的圖片其實就差不多一致了。
由於 Render 的工作內容已由 ReactJS 取代掉了,
所以 Flux 資料流中並沒有出現這個角色在。
今天要展示的 JavaScript 需求如下︰
看到這可能一堆人會說「根本是在汙辱我」、「很簡單啊」
舉 jQuery 來說好了,
來個監聽 input keyup 事件就搞定了。
但篇幅就是要來介紹如何不使用 Framework 並且套入 Flux 架構去完成。
而不是用各位熟悉的框架去達到此目的。
先定好下方的 HTML。
一般如果要監聽會經常看到以下這樣寫︰
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', function(){
//do something...
});
this.inputBox.addEventListener('keyup', function(){
//do something...
});
}
};
如果想要把 function 獨立出來可以這樣變化︰
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this.clcik1);
this.inputBox.addEventListener('keyup', this.keyup1);
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
如果再 click1 跟 keyup1 中想使用 dispatcher 的變數或方法︰
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this.clcik1.bind(this));
this.inputBox.addEventListener('keyup', this.keyup1.bind(this));
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
到目前為止大家應該都能接受,
如果要切的乾淨就再把 function 切出去。
但是重新檢視一下我們的 Flux 視圖,
我們應該要把元素跟事件分離乾淨,
所以需要把事件註冊到統一的分配器,
再針對不同的事件做處理,
這時候我們就可以用到 JavaScript 內建的 handEvent 了。
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//監聽
this.displayBlock.addEventListener('click', this);
this.inputBox.addEventListener('keyup', this);
},
handleEvent: function(e){
switch(e.type){
case 'click':
switch(e.target){
case this.displayBlock:
this.click1();
break;
}
break;
case 'keyup':
switch(e.target){
case this.inputBox:
this.keyup1();
break;
}
break;
}
},
click1: function(){
//do something...
},
keyup1: function(){
//do something...
},
};
這樣就完成了呼叫的統一了,
而且也不用寫 bind(this) 就能呼叫到 dispatcher 內的變數與方法。
如果需要反註冊的話可以使用︰
this.displayBlock.removeEventListener('click', this);
為了將資料處理分離,我們需要一個 Store (資料處理器) 來負責處理,
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
getSomething: function (){
return this._data;
},
setSomething: function (val) {
this._data = val;
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
//click 事件在此需求無需關注
//this.displayBlock.addEventListener('click', this);
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
}
//略
};
資料分配器 Store 應該避免掉從外部直接改變
可以在呼叫端使用 window.DispatchEvent 發送自訂事件 CustomerEvent ,
並在 Store 內接收自訂事件去做到。
所以在觸發行為時也不會去撰寫 Store.doSomething()
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
init: function(){
window.addEventListener('store_set',this);
},
handleEvent: function (val) {
switch(e.type){
case 'store_set':
this.setSomething(e.detail.val);
break;
}
},
getSomething: function (){
return this._data;
},
setSomething: function (val) {
this._data = val;
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
this.store.init();
},
handleEvent: function(e){
switch(e.type){
/*
case 'click':
switch(e.target){
case this.displayBlock:
this.click1();
break;
}
break;
*/
case 'keyup':
switch(e.target){
case this.inputBox:
//觸發自訂事件
window.dispatchEvent(new CustomEvent('store_set',
{'detail':{'val':this.inputBox.value}}
));
break;
}
break;
}
}
// click1() & keyup1() 這2個假事件可以拿掉無需關注
};
最後來做出 Render 來改變畫面,
透過 Store 發送通知 Render 來繪製。
Render.js
var Render = {
init: function(element, Store){
this.element = element;
this.store = Store;
window.addEventListener('render_view', this);
},
handleEvent: function(e){
switch(e.type){
case 'render_view':
this.element.textContent = this.store.getSomething();
break;
}
}
};
Store.js
function Store() {
this._data = 0;
}
Store.prototype = {
init: function(){
window.addEventListener('store_set',this);
},
handleEvent: function(e){
switch(e.type){
case 'store_set':
this.setSomething(e.detail.val);
break;
}
},
getSomething: function () {
return this._data;
},
setSomething: function (val) {
this._data = val;
window.dispatchEvent(new CustomEvent('render_view'));
}
};
Dispatcher.js
var Dispatcher = {
init: function(){
this.displayBlock = document.getElementById('DisplayBlock');
this.inputBox = document.getElementById('InputBox');
this.inputBox.addEventListener('keyup', this);
this.store = new Store();
this.store.init();
Render.init(this.displayBlock, this.store);
},
handleEvent: function(e){
switch(e.type){
case 'keyup':
switch(e.target){
case this.inputBox:
//觸發自訂事件
window.dispatchEvent(new CustomEvent('store_set',
{'detail':{'val':this.inputBox.value}}
));
break;
}
break;
}
}
};
Dispatcher.init();
所以上述程式碼實現︰
由 Dispatch 註冊 Render,並傳入 Store 與所需的 View 元件,
資料更新完全由 Store 控制,
Render 去渲染 View 元件。
透過大量的 handleEvent 降低邏輯,資料,與介面元件之間的關聯程度。
之後再去研究 Flux 與 ReFlux 應該也比較好上手。
以上程式範例參照 Gasolin 發表的一篇漸進改善程式碼的組織方式的文章加以修改。
友善連結︰
訂閱:
文章 (Atom)