2015年9月10日 星期四

軟體工程書摘與心得 Part 2:物件導向軟體工程之另類思考

延續上篇,當我們有完整的需求分析後,接下來就是要實作程式碼。這部分我跳過很多,直接把我認為重要的拿出來。當類別圖畫好後,接下來就是要畫出序列圖(Sequence Diagram),之後對使用者案例進行健全性分析,最後連接上對於該程式的領域模型,之後軟體內類別和類別的關係大抵上就確定了。

物件導向的另類思考流程圖
至於什麼是序列圖?就是在一個動作中,列出參與該動作的物件,隨著動作進行時,找出物件和物件之間的交互子動作,直接看例子:

Sequence_diagram_for_handling_a_browser_request_using_the_Model_View_Controller_MVC_pattern

上圖中顯示要「處理來自瀏覽器的請求」時,所需要做的動作和參與的對象,隨著動作開始進行,首先Browser會發出HTTP GET Request()給Tomcat,之後就持續做一連串的動作,直到整個流程被完成。序列圖的好處是(1)知道參與者有哪些,(2)子動作其實會對應到所實作的函數,能很直覺地反映出程式該怎麼寫。

另外還有一個是健全性分析(Robust Analysis),他是把「分析的模型轉換成設計的模型」。依據使用案例模型,輸入使用案例、使用案例的情況(Scenarios)、使用案例對應的活動圖(Activity Digram),以及領域模型,輸出成以UML表示的合作圖(Collaboration Diagram)來記載,裏頭會有3種主要的設計成員:
  1. 邊界物件(Boundary Objects):用來描述系統與角色之間的互動
  2. 實體物件(Entity Objects):用來描述系統中經常存在的資訊(Persistent Information)
  3. 控制物件(Control Objects):用來描述對於其他物件的控制、安排,或是協調
使用健全性分析是幫助釐清目前定義的類別是否足夠、角色定義是否明確,可能在進行健全性分析的過程中會發現更多的物件或是新的屬性類別,然後用來重新繪製序列圖,所以序列圖的建立不是一次就完成的,是需要經過多次迭代的。

我覺得最厲害的還是序列圖,他可以直接讓我知道怎麼寫程式,同時又能了解物件的互動,真的很值得學習。

下一篇要介紹當軟體完成時怎麼做系統組態的管理與維護,如何讓軟體能適時地反映使用者的成長


2015年9月9日 星期三

軟體工程書摘與心得 Part 1:為何需要軟體工程&軟體工程之簡介

最近閒來無事去看了Livecoding.tv上程式設計師表演打code,就覺得怪了為何你腦袋能源源不絕想出接下來要做什麼,從這頁面又跳到下個頁面,雖然我也能看懂你在做啥,可是自己就不一定能這樣行雲流水般地打code(苦笑)。後來想想應該是我缺乏軟體工程上的訓練。

不然別人是怎麼會想說這邊要用這個protocol?下一個地方要用這個函數銜接?在軟體工程中我從這本書找到了答案:

根據書中解釋,1960年代末期由北約召集科學家探討「軟體危機」的問題,討論如何有更好的軟體開發方法來提升開發的效率、節省開發成本,同時獲得良好的軟體系統品質,因而催生了軟體工程的發展。對我來說寫軟體就如同建造房子,從畫藍圖、打樑樁等都有一套步驟和分析的方法,都需要投入大量的精力來完成。

而這也是會和有些人能把程式寫得穩健、可靠、可擴充,就是有進行完整的系統分析、需求了解、介面設計等才能達到一定品質。隨著軟體漸趨複雜,光是作業系統就可高達上千萬行程式碼,如何做好軟體開發就需要系統工程的幫忙,並借助軟體系統開發方法論,然後選擇軟體開發程序:

  1. 傳統階梯式的軟體開發程序:做好需求分析後,設計系統與軟體的架構,之後進行系統製作與局部測試,最後整合測試後就可上線使用還有維護
  2. 漸進式的軟體開發:透過需求分析後快速產生原型,之後陸續迭代產生新產品
  3. 需求規格化的軟體開發程序:將軟體系統的規格以數學模型來表示,之後自動轉成程式碼
  4. 組合式的軟體開發程序:分別完成系統內的各個元件,之後再組合起來
而隨著物件導向的盛行,也陸續產生新的開發方法(其實也很久的東西了):
  1. RUP (Rational Unified Process):結合螺旋式、反覆式及漸進式的開發方法,主要分成「開始階段」、「細化階段」、「建置階段」、「轉換階段」四種
  2. 敏捷開發:像是XP(Extreme Programming)、Scrum等
方法演進後手上的工具也不能輸人啊!因此就有電腦輔助軟體工具(CASE, Computer-Aided Software Engineering)的出現,早期CASE工具出現時人們的期望很高,認為可以大幅下降軟體開發成本,但當時的CASE工具並不成熟,沈寂了一段時間後大家才開始陸續使用,大家常用的IDE就是一個典型例子。

仔細回想起來,目前有很多火紅程式教學的網站,大家都用得開心,可是真的要開發一套系統就只能坐在電腦前打不出任何東西,一部分可能是程式技巧不足,另一部分就可能是缺乏軟體工程的訓練。當了解軟體工程時,就能超越一般的程式設計師成為軟體工程師,就像是從一位工人進化到建築師,從只會寫程式變成能洞悉大局、了解如何規劃與參與軟體開發的各個階段的「高級程序員(猿)」。

下一篇將會介紹軟體系統的需求工程,如何找到需求並把需求轉成軟體架構、規格就需要這篇啦~

2015年9月2日 星期三

iOS Push/Local Notification之原理

這次來介紹一下如何使用iOS上的Push Notification,舉凡Facebook上的訊息、Gmail的郵件通知都是此類。而首先就是要知道Notification有分成Local和Push兩種,前者像是行事曆的定時通知,後者就是前面講的。Local的通知好處理,可以指定日期和時間來通知:
 NSCalendar * calendar = [NSCalendar autoupdatingCurrentCalendar];

NSDateComponents * dateComponent = [NSDateComponents alloc] init];

[dateComponent setDay: item.day];  // item: self defined object

[dateComponent setMonth: item.month];

[dateComponent setYear: item.year];

[dateComponent setHour: item.hour];

[dateComponent setMinute: item.minute];

NSDate * date = [calendar dateFromComponents: dateComponent];



 UILocalNotification *localNotif = [[UILocalNotification alloc] init];

 if (localNotif == nil)

    return;

localNotif.fireDate =

[date
  dateByAddingTimeIntervalInterval:-(minutesBefore*60)];

 localNotif.timeZone = [NSTimeZone defaultTimeZone];

 localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"%@ in
  %i minutes.", nil),
           item.eventName, minutesBefore];



localNotif.alertAction = NSLocalizedString(@"View Details", nil);

localNotif.alerttitle = NSLocalizedString(@"Item Due", nil);

localNotif.soundName = UILocalNotificationDefaultSoundName;
      localNotif.applicationIconBadgeNumber = 1;

NSDictionary *infoDict = [NSDictionary dictionaryWithObject:item.eventName
  forKey:ToDoItemKey];

localNotif.userInfo = infoDict;

[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];

那麼要設定Push Notification要怎麼做?首先要用Apple的Push Notification機制(簡稱APN),自己的Server發出通知後會傳到Apple的Server,之後再從Apple傳給使用者的App:


我覺得這樣做的原因是要保持通知的完整性和安全性,假如說你傳送有惡意訊息的封包給使用者豈不是不好?而建立整個連線流程如下圖所示,裝置先和APN建立TLS(Transport Layer Security)連線,之後取得憑證後TLS就算建立完成:

而Provider也是同樣要建立TLS連線和取得憑證:

而當憑證建立完成後App和APN, Provider的互動就是靠Token來完成,App若要使用Push Notificaition必須先行註冊至APN(從使用者那邊獲取通知許可),然後APN再回傳加密過的Token給Provider,之後該Token再從Device回傳到Provider,如下圖所示:
而在傳送Push Notification時會連同Token,並藉由裝置ID來回傳加密的通知內容給裝置:

到這邊整個Push Notification就算完成,接下來就是在AppDelegate.m加上程式碼:

// Remote notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    NSLog(@"Receive deviceToken: %@", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"Remote notification error: %@", error.localizedDescription);
}
另外當收到了Notification後要做什麼事就先靠didReceiveRemoteNotification來完成,而handleActionWithIdentifier則是當使用者對Notification做出回應後你要採取什麼動作時,可用completionHandler的block來完成:

// When app is waked up, this method will be called
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    // with push notification from remote server
    // When app is running in the foreground, this method will be called
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler{
    // Test for identifier with a sample indentifier
    if ([identifier isEqualToString:@"ACCEPT_IDENTIFIER"]) {
        [self handleAcceptActionWithNotification:userInfo];
    }
}
以上就是整個流程,至於說要註冊憑證的方法可參考這篇:popcorny的碎碎念