2013年12月30日 星期一

Android 開發 (八) Parcelable 使用

序列化

在android中,將資料在頁面間傳遞的其中一個方法就是將資料序列化以後保存在bundle內
Serializable是java的序列化,要實作非常簡單,只需要將以下的code 輸入即可

class PersonSerializable implements Serializable
{

 private static final long serialVersionUID = 1L;
 String name;
        //...other properties
}


Parcelable 是android內部輕量級,高度最佳化的序列化協定,
簡單的說,在程序間的溝通建議使用 Parcelable。


如何使用Parcelable?

1.使用parcelable需要實作 Parcelable (廢話....)
2.必須實作 writeToParcel
3.必須實作 CEATOR(public static final 變數)
sample 如下


class Person implements Parcelable {

 String name;
 

    protected Person(Parcel in) {
        name = in.readString();
    }

    public Person() {
  // TODO Auto-generated constructor stub
 }

 @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }

    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
}

說實話... Parcelable實在不是很好實作,尤其是class 裡面有其他class或者 property一堆的時候
不過為了最佳化我還是花了點時間survey,
最後,我找到了下面這個網址  http://devk.it/proj/parcelabler/
使用方法很簡單,將以下的程式丟入Code section內  並按下 Build

class Person implements Parcelable {
 String name;
}

他就自動幫你產生好所有必要的程式碼了!!~
最後,讓我們大喊一聲自動化萬歲~

2013年12月25日 星期三

Git (六) 分支

分支是甚麼?

分支就是在專案中開闢新的開發線,當切換分支時檔案也會同步為新分支的檔案
例如
在 hello2中
做了三個commit
vi MasterA
vi MasterB
vi MasterC
git add MasterA
git commit -m "MasterA"
git add MasterB
git commit -m "MasterB"
git add MasterC
git commit -m "MasterC"

然後 git checkout -b pp   創建一個分支名叫 pp 並將分支切換到  pp
並做一個commit
vi  branch
git add branch
git commit -m "branch"
這時候開發圖會長得如下圖所示


這章圖代表甚麼呢?

代表在同一個專案中目前有兩個分支分別是 pp 以及 hello2
兩個專案中所擁有的檔案並不會相同 hello2中擁有 masterA masterB masterC
而 pp中只有 branch這個檔案

簡單的說可以在同一個資料夾底下同時存有多個不同版本的檔案


為什麼要開分支不開另一個資料夾?

原因其實很簡單,使用分支的好處太多了,
舉個例子,假設我今天有兩個分支
ACompany 和 BCompany 這兩個分支所代表的意義分別是給A公司的客製化版本,另一個是給B公司的客製化版本,基本上程式架構都相同,只有某些功能有些差異,
假設今天在ACompany分支上完成了一個新的feature,
然後BCompany分支也要導入這個功能時,我們只需要使用cherry-pick就可以將功能導入,
我們可以很輕易的將功能導入。

如果是使用另一個資料夾就必須花時間apply patch或者重新將功能導入(我想不會有人想這麼做)
而且很難做兩個版本之間的控管


何時要使用分支?

  • 當出現多種版本要維護時,例如出了1.0版本 2.0版本但是兩個版本都還有人使用這時候就可以開分支,當出現bug時可以同時做兩個版本的修復
  • 開發版本,測試版本,正式版本,這種作法是為了幫助自動化測試,在正式版本或測試版本通常會有dayly build 和 unit test 在run 只要有新的commit 就會做測試, 開發人員將開發好的版本merge 進測試版本 經過測試之後再進到正式版本。
  • 開發新功能時(這是本人較習慣的做法),在開發新功能時先開立一個新的分支在功能完成後再將該分支merge回去。這樣可以避免主支幹擁有尚未完成的功能,而其他人還是可以繼續做commit 的動作
養成好的分支觀念,可以讓開發以及維護更順利,遇到以上的情形,just Branch It  XD



Git (五) reset 應用 merge 和 rebase之後的倒回

由  Git 常用指令 (一) git reset  可以瞭解 reset 可以將檔案倒回,
這裡要說明的是,當merge 或 rebase之後要怎麼將版本倒回尚未下指令之前,
首先要介紹一下幾個特別符號

HEAD  

為分支上最新的送交

ORIG_HEAD

在merge 或 rebase 時 ,會先將原本的HEAD記錄在 ORIG_HEAD ,
所以可以使用ORIG_HEAD來做恢復的動作

FETCH_HEAD

是抓取的上一個分支HEAD,並且僅在抓取指令之後有效,使用這個符號可以找到git fetch 指令抓取的HEAD

MERGE_HEAD

合併再執行時,另一個分支的HEAD會被暫時的記錄在MERGE_HEAD中


所以,回到merge 或 rebase時該怎麼倒回
就是使用 git reset --hard ORIG_HEAD  將檔案倒回就可以了


2013年12月24日 星期二

OOAD原則 (九) 封裝

何謂封裝?

對資料所做的任何計算都受到保護,因為資料不會被存取。
也就是隱藏程式執行內部事物的部分。

舉個例子

Ted.gotoTaipeiStation()
Bob.gotoTaipeiStation()

有時候我們只在乎 Ted and Bob 都到了台北,我們不會去care
Ted 住在台北  所以他搭捷運到北車
Bob住在台南,所以他必須搭高鐵到北車

封裝隱藏了實際實作的部分。



封裝在某些情況也避免了使用者錯誤的操作

例如

networkParser.getUserData()
dbParser.getUserData()

networkParser的動作可能包含了
1.連到網路 2.取得正確網址 3.取得資料 4. 擷取UserData

dbParser得動作可能包含了
1.連線到db 2.query db table資料並取得資料

但是使用者不需要知道詳細的情況,使用者只需要知道現在要拿userdata就好了
封裝讓使用者輕易的取得UserData,而不需要實際去操作,這避免了使用者錯誤的使用


該如何使用封裝?
可以看看以下的範例


interface GotoTaipeiBehavior
{
 void gotoTaipeiStation();
}
class Ted implements GotoTaipeiBehavior
{

 @Override
 public void gotoTaipeiStation() {
  // TODO Auto-generated method stub
  System.out.println("Tkae SubWay");
 }
 
}

class Bob implements GotoTaipeiBehavior
{

 @Override
 public void gotoTaipeiStation() {
  // TODO Auto-generated method stub
  System.out.println("Tkae HightSpeedRail");
 }
 
}
public class person {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  GotoTaipeiBehavior behavior = new Ted();
  behavior.gotoTaipeiStation();
  behavior = new Bob();
  behavior.gotoTaipeiStation();
 }

}

這個範例就說明了 Ted 和 Bob去台北車站的例子,
main裡面就是client使用時呼叫 ted 和 bob 要去台北車站,
可以注意到這邊我們只在乎他們的行為(GotoTaipeiBehavior )不在乎他們是誰,
在我們將Ted 或Bob 創建出來之後,我們將他們一視同仁(都是behavior),然後要去台北車站,
這樣寫的好處是,不管是誰要去台北車站都可以使用gotoTaipeiStation這段程式,
程式的可用性提高了,而且使用者不需要知道裡面實際做了甚麼事情,只需要知道人到了台北,這同時也提升了程式的可讀性。


結論

封裝會隱藏物件的實做,以及保護資料避免被user操作,同時他也可以將某些user不需要知道資料隱藏起來(例如某些控制開關的flag)。
封裝可以降低程式的耦合度,同時若加上良好的命名封裝同時也可以提升程式的可讀性,進一步提升了程式的維護性。

2013年12月23日 星期一

Git (四) Rebase vs Merge (續)

在上一篇有講述rebase 和 merge上的差異,這篇要講的是線圖上的差異

先看看下面三張圖表


原圖



Merge


Rebase


rebase 可以將線圖拉直,merge則是會將兩個線圖合併
rebase的好處是可以將branch的紀錄消除(在線圖上就不會看到兩條線)
在使用上是看個人喜好,不過在使用rebase的時候要特別注意
網路上有人認為rebase is evil,他們認為

When you rebase a branch, you are changing its history in a way that will cause problems for anyone who already has a copy of the branch in their repository and tries to pull updates from you.

意思是如果在某個很多人使用的branchA下,rebase另一個branchB,然後又將rebase之後的結果push出去,會使得該branchA的共同使用者遇到問題。

大部分的人都建議 rebase只用在private branch,


使用情境大概是

我在master上開一個branch 然後在上面實作了自己的功能,經過一段時間之後,我發現master經歷了許多版本的update,所以我希望將branch update到最新版本,以便於測試是否有問題,
這時候就可以使用 rebase 將我自己的branch update到最新版本。

不過..我的做法是會再新開一個branchC 然後將branchC 做rebase,就如同上面英文所說的,
rebase會更改歷史記錄,假設rebase失敗了,那local的檔案也會跟著毀掉,所以保險起見,我還是會先做個備份。


不建議的做法是

在一個眾多人參考的branch上開發了自己的功能,經過一段時間之後,發現跟server上的branch版本有差異,所以使用rebase 將版本 update到最新版本。

這兩個的差異就是在於一個是私人的branch 不管怎麼改都不會影響到別人
但是共用的branch如果操作錯了不僅整個分支會出問題,還會連帶影響到其他的開發人員,
這是很可怕的事情。


2013年12月22日 星期日

敏捷開發(一) 開始研讀敏捷開發書籍的原因

趁我還有印象的時候,寫下之前不好的開發經驗

1.RD 包攬 PM QT的事情

是的,RD需要常常跟其他部門溝通,提供需求給其他部門,跟各窗口討論我們需要的功能,還得去開會了解一些進度的問題,這樣來來回回非常浪費時間。
而QT測回來的東西,RD常常會很難複製,或者QT描述的複製手法很不清楚,必須經過多方溝通,非常浪費時間。

這部分我深深覺得哪裡有問題,但是我也不知道該如何下手。
或許需要將合作的單位都拉在附近一起做事吧,有問題可以直接溝通,直接反應,直接解決,這樣或許就可以省去大量來回的時間。

2.定好的SPEC總是很輕易的翻盤 

UI這禮拜說要這樣畫,然後下禮拜又說要換另一個形式,總是在修改,彷彿RD不需要花時間去架構設計coding一樣,然而project的deadline並沒有因為這些修改而改變,
我其實很好奇這樣的做法是否真的正確,感覺是在哪一環出了問題。

仔細思考之後感覺是上層主管太慢看到成品,通常demo的都是成品,然而這時候才有意見要修改,就必須花很多時間修改,感覺應該要有個代理人,我們可以在每個禮拜或每個月release一個版本給他看,如果代理人有任何的想法應該在那時反應,在這個階段修改,然後之後就不應該再有修改,除非是等到新的版本或者下個schedule才將新的修改加進去。

3.schedule總是定得很短

這使得RD沒有時間可以架構設計,而是直接將手邊有的想法直接倒入程式內,沒有經過多餘的討論,代價就是可怕的架構,難以維護的程式碼。

4.spec更改,RD最後一個知道

某個案子需要跟別的team合作,有些資料必須靠他們的api傳遞給我們,但是...常常spec更新了或修改了我們這邊都沒有人被告知,直到QT測出問題了,我們這邊才知道出事了。
又或者某次UI做了變動,卻沒有同步道所有的人,大家的認知不同,做出來的東西也有誤差。

這部分我深深覺得是彼此溝通的問題,資料沒有同步,我想各單位合作時必須要有個共同溝通平台,或者是能夠同時update彼此最新的進度,並check是否有哪邊是沒有同步到的



run過這樣的案子之後,我對現行run的方式有很大的疑問...
真的是這樣run的嗎???  這句話不斷在我腦海中重複出現

為了能夠解除我內心的疑惑,我花了點時間開始翻閱一些書籍,然後偶然間聽到了敏捷開發,發現裡面的一些想法似乎能解決掉上面大部分的問題,所以,我就這麼踏進了敏捷開發這個世界....也期許在這裡能夠找到我要的答案!!

2013年12月19日 星期四

Git (三) cherry-pick

Cherry-Pick

這個指令讓我們能夠將branch中,某一次commit所做的修改,直接套用到另外一個branch
如下圖所示


上圖 develop 為主要的開發支幹,
然後我們開了一個branch "feature/TestFeature" 然後在那個branch做了一些資料的更改,
接著我們希望將其中four 所做的變更套用至 develop 中,這時候就可以使用cherry-pick


接下來我們要將four這個commit 套用至 develop中
所以首先我們要先知道 four 這個commit 所代表的"代號"  也就是 b784dfe 這組數字
接著在develop branch中下指令 git cherry-pick b784dfe 就可以了


如下圖所示,four這個commit直接被套用到 develop中



cherry-pick 可以讓我們將部分的修改直接套用到另一個branch


使用的情境

同時在維護兩個類似的project
當修正完A project的 bug之後  只需要使用cherry-pick將相同的修正套用到B project即可
這算是十分方便的功能