MR SHIH

必幸施

iOS 大量網路與硬碟I/0處理

| Comments

很多時候操作網路或者Disk的I/O,我們都會把工作丟到背景去執行,避免凍結使用者的畫面。但是這造成一個問題是一下子太多背景任務同時執行有可能導致APP崩潰。

比如影音APP使用者見獵心喜,一下子選了許多部影片要下載,如果現在把下載任務一股腦兒丟到背景,因為現在大部分下載需求都直接使用知名框架AFNetworking,而裡面的方法通常也都直接在背景運行,造成這些下載任務用Concurrent的方式併發執行,這下子產生大量的網路還有Disk I/O Request同時在背景跑。

UI是不會被凍結沒錯,但很有可能背景操作網路或Disk I/O的量太多(通常是Disk),導致APP崩潰。

以Serial思維執行背景任務

這時候就非常建議一次下載並儲存一部影片就好。也就是確保上個任務執行完畢,Queue在推送下一個任務去執行。

混亂的完成順序

直觀的實作方式就是建立一個Serial Queue,把需要列隊執行的任務用dispatch_async加入進去,就像以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 建立一個唯一的Serial Queue
dispatch_queue_t _uploadToParseInBackgroundQueue() {
    static dispatch_once_t queueCreationGuard;
    static dispatch_queue_t queue;
    dispatch_once(&queueCreationGuard, ^{
        queue = dispatch_queue_create("com.shih.secureMedia.uploadToParseInBackgroundQueue", DISPATCH_QUEUE_SERIAL);
    });
    return queue;
}

// 包含一個異步方法的Method
(void)addTaskUploadMovie(NSDate *)movie
dispatch_async(_uploadToParseInBackgroundQueue(), ^{

    NSLog(@"%@上傳Start.......",movie.name);
    // 某個很花時間,但本身已經是丟到背景處理的方法
    [self uploadMovieInBackground:movie withCompleteBlock:^(BOOL succeeded, NSError * _Nullable error) {
        NSLog(@"%@上傳Done",movie.name);
    }];
});

實際執行:

1
2
3
4
[self addTaskUploadMovie:a];
[self addTaskUploadMovie:b];
[self addTaskUploadMovie:c];
[self addTaskUploadMovie:d];

這裡有個大問題是uploadMovieInBackground本身已經是跑在背景,所以四個上傳任務實際上在後台是以併發Concurrent/Parallel的方式執行。

而多個高I/0負載任務被同時執行就有可能造成APP崩潰。

實際執行結果會像這樣,但實際上不可預測,因為不能知道哪個會先完成:

1
2
3
4
5
6
7
8
a上傳Start.......
b上傳Start.......
a上傳Done
c上傳Start.......
c上傳Done
d上傳Start.......
d上傳Done
b上傳Done

可控制的完成順序

而如果你希望上傳程序按照以下Serial的邏輯去跑:

1
2
3
4
5
6
7
8
a上傳Start.......
a上傳Done
b上傳Start.......
b上傳Done
c上傳Start.......
c上傳Done
d上傳Start.......
d上傳Done

加入dispatch_suspenddispatch_resume

加入這兩個操控Queue的方法就是做兩個目的:

  • 當某個在Serial Queue的上傳任務Block被執行的時候,此任務在Block內馬上呼叫Queue的Suspend方法,來暫停這個Queue繼續執行下個上傳任務

  • 而當前上傳任務執行完成之後,在該任務的call back block裡面馬上呼叫Queue的Resume,來讓下個上傳任務被執行

反覆上述行為就達到我們要的一次在背景做一件事情的效果了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(void)addTaskUploadMovie(NSDate *)movie
dispatch_async(_uploadToParseInBackgroundQueue(), ^{

    NSLog(@"%@上傳Start.......",movie.name);
    // 某個很花時間,但本身已經是丟到背景處理的metod
    [self uploadMovieInBackground:movie withCompleteBlock:^(BOOL succeeded, NSError * _Nullable error) {
        NSLog(@"%@上傳Done",movie.name);

        // 這個Task執行完了,讓Queue resume,讓排在下一個的Task可以被執行
        dispatch_resume(_uploadToParseInBackgroundQueue());
    }];

    // 上面的uploadMovieInBackground開始後,就暫停這個Queue,不再執行Task(外部依然可以隨時用dispatch_async Passing Task)
    dispatch_suspend(_uploadToParseInBackgroundQueue());
});

dispatch_resume與dispatch_suspend的官方參考文件

推播結合背景更新 - 良好的使用者體驗

| Comments

試想一個情境是相簿APP在後台收到伺服器傳來愛人分享的最新照片,但使用者興沖沖的打開之後面對轉阿轉不停的Loading indicator圓圈圈,多麼令人掃興。 動通知但被動下載資料顯然不是一個好方法。

這個時候可以透過推播通知APP,並在背景讓程式預載相片,載好之後再通知使用者點開APP,立即可以看到所有相片,多棒的使用者體驗。

要不打擾到使用者偷偷通知手機要實作Silent Notification,很簡單,只要加上content-available=1,再來把alert,badge,sound全部留空就好,並且在Xcode的Capabilities->Background Modes->Remotes Notification這裡把選項打勾。

這時候當手機收到有content-available=1的推播,iOS就會在背景喚醒你的APP,並且呼叫下面方法讓你下載資料或做些事,下次使用者打開就可以看到更新的內容了:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)application:(UIApplication * _Nonnull)application didReceiveRemoteNotification:(NSDictionary * _Nonnull)userInfo fetchCompletionHandler:(void (^ _Nonnull)(UIBackgroundFetchResult result))handler {

  // 下載資料...

  // Local Notification提示使用者下載好囉
  UILocalNotification *locNotification = [[UILocalNotification alloc] init];
    locNotification.alertBody = @"Data have arrived!";
    [[UIApplication sharedApplication]presentLocalNotificationNow:locNotification];

  //回調系統下載好了
  handler(UIBackgroundFetchResultNewData);
}

…the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again……

As soon as you finish processing the notification, you must call the block in the handler parameter or your app will be terminated. Your app has up to 30 seconds of wall-clock time to process the notification and call the specified completion handler block….

官方文件說有例外,就是使用者曾經手動殺掉過這個APP,奇怪的是在我的開發經驗裡面,就算使用者手動殺掉系統在收到推播之後還是會去喚醒這個APP。

然後系統大約會給你30的時間讓你去下載需要的資料到記憶體或硬碟,之後就必須要call handlerUIBackgroundFetchResult告訴系統已經載入完畢。

如果成功下載了我們要的資料,就可以發一個LocalNotification來通知使用者來享用你剛下載好的檔案,一打開就有下載好的內容,多棒的使用者體驗啊。

iOS 在不同ViewController指定Status Bar

| Comments

查看文擋很容易發現viewController有個preferredStatusBarStyle接口,搭配語意明顯的setNeedsStatusBarAppearanceUpdate,看起來可以指定回調的UIStatusBarStyle比如白色與黑色。但時常調用了卻沒有回應。

這時候查一查文擋內相同Section附近的API會是個好習慣。在Managing the Status Bar裡發現下面這個接口:

1
- (UIViewController *)childViewControllerForStatusBarStyle;

按照苹果官方的解释:

If your container view controller derives its status bar style from one of its child view controllers, implement this method and return that child view controller. If you return nil or do not override this method, the status bar style for self is used. If the return value from this method changes, call the setNeedsStatusBarAppearanceUpdate method.

調用setNeedsStatusBarAppearanceUpdate時,系統默認會去調用application.rootViewController的preferredStatusBarStyle方法,所以這時候當前自己的viewController的preferredStatusBarStyle方法根本不會被調用。

這個接口很重要,這種情況下childViewControllerForStatusBarStyle就有用了。一般我們常用navigationController作為rootViewController,利用此接口便可以很方便自訂各個viewController的statusBarStyle。 子類化一個navigationController,並且overridechildViewControllerForStatusBarStyle

1
2
3
- (UIViewController * _Nullable)childViewControllerForStatusBarStyle {
    return self.topViewController;
}

意思就是說不要調用我自己application.rootViewController(navigationController)的preferredStatusBarStyle方法,去調用`childViewControllerForStatusBarStyle`回傳的UIViewController的preferredStatusBarStyle。這裡回傳self.topViewController就可以保證當前顯示的viewController的preferredStatusBarStyle會被系統調用且正確的顯示。

回看行動趨勢與我這三年

| Comments

無盡的新元素

過去三年陸續加上了穿戴式裝置,無人飛行機操控,行動支付,線上串線下服務(我其實很不喜歡文鄒鄒名詞,這裡指的就是Uber,airbnb等把供應者與消費者串起來的服務),車用APP等新元素,到底這些對於一個APP開發者的影響是什麼?

2013開始的混沌應用時代

當時最簡單最簡單的APP開發者應用就是加入銀行或者是媒體,幫他們寫APP。我在那時候發現各大媒體寫出來的新聞APP點進去以後是Web View,裡面有大量Javascript加上3G連線速度慢,所以很多人在當時看新聞APP是痛苦的,於是我寫了一個APP單純載入HTML並把內文Parser出來,只剩下純文字,但載入時間從一般Web往往要5~6秒,降低到1秒以下,整個看新聞體驗變得是很愉悅的,而這個APP在當時也如願衝到台灣新聞類付費下載第一名,整個從開發到上架都是一手包。題外話是當時有媒體公司發函說要告我,很可惜當初沒告,不然我覺得事後發展會很有趣。

但後來去馬祖當兵也就沒有維護這個APP,之後媒體公司寫的APP也都從善如流把Web view拿掉,改成直接call api給內文,並且用native的方法顯示出內文。很高興成為台灣先驅。

事後來想,當初應該把這APP改成免費,衝高流量,反正後端提供內容的Server不是我的XD,並在下面加上如Instagram般很輕量的討論功能,之後搭配Google analytics把大家有興趣的新聞做成Facebook post(這功能其實有加入,但當時沒想法要拿來做什麼) ,用現在蘋果日報粉絲頁的方式操作,流量一定非常高,我就可以來去跟媒體業談談要不要跟我配合做網路新聞散播,我相信結果會很不一樣的。但當時想法實在太小,只想寫一個方便大家的APP。

這時期也接觸到amazon的cloud服務,從租ec2開始摸linux架起lamp,到租s3搭配php sdk做圖片儲存(那時候大學專題做的題目需要存圖片),搭配nginx還有apache,做出動靜態網頁sacble,這一連串摸索架起後台的實戰經驗純粹就是好玩,但後來幫助我許多,讓我日後再用parse的時候遇到問題可以大略推斷問題是出在我這邊還是parse那邊。不會之前然而不知其所以然。

串接facebook sdk也是在這時候接觸的,大致上是拿來做single sign on,然後能po文到使用者的timeline上。對於參與設計一個給很多人使用的sdk我十分嚮往,等等下面再舉例子。

這時期的下一個爆點是線上串線下服務,在台灣有EATABLE為代表。不知道為什麼最近demo day還是有很多人做訂餐廳服務,很想聊一聊是經過怎樣分析決定再跟EATABLE競爭。

2014往線下滲透與硬體

印象最深刻莫過於Uber,這APP是目前我花錢花最多的APP,遠遠大於其他APP所加起來的總合,你可以說他是吸金功力很強的APP沒錯,儘管Uber依舊虧損,但那龐大的金流量足以吸引無限創投砸錢讓它燒。Airbnb在台灣也可用到了,兩者在單純服務的背後都有很遠大規劃。比如Uber想作物流配送,Airbnb在租房背後考量到為出租者提供打掃,維護等服務,衍伸出來的許多應用這就是老外厲害地方,很會也很敢去想Bussiness model,這也是我在13年做得不足的地方。

技術上這時期出現了maker運動,自從arduino的爆發,如四旋翼攝影機,小機器人到未來的車控APP,這些在未來我相信都是用手機來做遙控,這時候如果具備有protocol撰寫的經驗,配合BLE或wifi等,對單純軟體APP工程師而言可以有另一片藍海。我在這年退伍並加入一家做穿戴式裝置的新創,就剛好學習這領域相關知識。

而在這間新創公司接觸到了aglie開發模式與超級無敵好用的git,這都是非常令我興奮可以學到的技能,畢竟git flow還是要配合同事一起使用才能像住精神時光屋一樣快速上手。

未來APP要考量的不只是單純的介面設計,與網路異步處理等很單純UI interface得部分,更有趣的部分比如Uber如何算出兩地的估計搭乘費用,怎麼根據資料算出熱門時段加成費率與什麼時候加,怎麼精確算出大約需要多久可以叫到附近計程車。這都是牽扯到資料後會產生很有趣的問題,通常也是人類真正關心的問題,也是能讓你的APP讓使用者真正覺方便好用的部分。這是非常吸引我的APP開發部分。

而你搭乘Uber所做的付款行為則是未來幾年最重要的兩項議題,資訊安全跟行動支付

2015資安與行動支付

行動支付在中國發展的最好,左岸同胞都很習慣用手機轉錢給其他人了,台灣礙於法規最近pchome才推出一款pi,創新敢做值得肯定,但在資安方面實在出太多包了,但沒關係,這也凸顯台灣資訊安全人才還沒有被擺道對的位置,也很有發展淺力。資安我focus在pki應用,我在過去曾今待過一家做pki應用的公司,對於資料傳輸過程中如何用非對稱金鑰搭配對稱金鑰保護資料不被竊取,如何做加解密有相關認識與實作,這也是因為當初偷連yahoo news原文api發現是明文之後覺得資安真的非常重要才把一些時間花在這個領域上面(yahoo news原文api現在有加密了)。這是我認為在技術上我有做對的事情。

行動支付在台灣分成傳統電子票證如悠遊卡陣營,與新興的電信與銀行陣營,其中電信與銀行聯合的陣營因為利益非配步履蹣跚,這是身為工程師我所看到的機會,未來一定很多領域想做支付也正在做,而做支付真的不外乎就是把資安搞好。我相信等Apple pay一開放來台灣,悠遊卡的優勢就需要注意,越來越多店家有paypass跟paywave,為了很潮與少帶一張悠遊卡,用手機付款是很吸引人的。未來還可以順便記帳呢。未來也很多如星巴克做自己的錢包,對於配合一家公司做一個錢包練功我也是很有興趣的。

在國外有paypal跟stripe,兩者都是service provider,差異很明顯stripe對開發者太友善,就像一家超有sence的網路公司,提供你一個簡單易用的SDK,甚至你在conslol就可以call post去call一個example交易範例,等於就告訴你我post也行,超簡單易用。未來設計Oauth等供其他人用的服務,提供很好用api與方便開發者的make sence SDK是未來幾年我有興趣想嘗試的大方向,scope夠大,牽連的技術應用範圍夠廣如scable,資安,data分析與挖掘(uber例子),這些都是符合我興趣的project的特性。

支付(含網銀與下單),通訊與社群,遊戲,新聞,串線下服務是我認為未來app五本柱,不脫離這些範疇,下次我會挑選我認為在這領域我欣賞的app與他得對手來寫出我的看法。

iOS Model-View-ViewModel 實作

| Comments

MVC架構遭遇困境

在iOS SDK的設計下開發者都會走向apple安排好的MVC架構,即便你不知道MVC但SDK早幫你切好view controller,很自然你也會走向類似架構。但隨著開發時間越長有幾個MVC框架問題越來越不可忽視。本文會先討論遇到的問題,並介紹最近我實作過覺得很棒的另一套架構MVVM,可以輕易讓程式碼彼此耦合降低,進而增加可維護性與易開發性,可以說是替代MVC更先進好用的架構。

在Model裡可能是Core data,也可能是sqlite,其中往往是提供幾個API回傳需要的資料,並且用NSArray等等簡單的包裝好後就丟給Controller去轉換成View需要的格式,在這裡Model的某些工作被丟給了Controller。

在View層就是xib,或是storyboard。用上面兩種起碼在排版上跟Controller分離,但如果沒有用Auto-layout就會需要設定freme,在這裡View該自己做的事丟給了Controller。還有一個狀況是透過IBAction直接在Controller裡面操作Model取得狀態,比如登入按鈕!這會讓登入邏輯落在許多不同地方,本身也增加了View跟登入功能細節的耦合,很明顯View不該接觸Model。

最大的問題是Controller負擔的工作實在太多,要從Model去轉換資料來更新管理的View,還要協調View與Model之間的互動,還有Loading狀態,各式各樣的Delegate與NSNotification,這引出了MVC的大問題

  • 過於肥大的Controller,動輒數千行
  • 無論如何View跟Controller會互相交錯,最後牽一髮動全身

用MVVM架構優化

MVVM是從MVC基礎上改進而來,所以可以很容易從現有MVC去做改進,以下範例就可以看到整合進MVVM是非常容易的 把所有資料轉換的邏輯寫到View Model

下面是一個範例的Calendar model還有配合得View Controller

1
2
3
4
5
6
7
8
9
10
@interface Calendar : NSObject

- (instancetype)initwithToday:(NSDate *)today;

@property (nonatomic, readonly) NSString *month;
@property (nonatomic, readonly) NSString *day;
@property (nonatomic, readonly) NSString *year;
@property (nonatomic, readonly) NSDate    *today;

@end

假設我們單純把Calendar裡面的日期印在cell上

1
2
3
4
5
6
7
8
9
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyyMMdd";
  NSString *date = [[dateFormatter stringFromDate:today] capitalizedString];
  
  [cell.todayLabel date];
  
}

以上是標準MVC普遍寫法。現在看看MVVM如何改進。以下使一個CalendarViewModel

1
2
3
4
5
6
7
@interface CalendarViewModel : NSObject

- (instancetype)initWithCalendar:(Calendar *)calendar;
@property (nonatomic, readonly) Calendar *calendar;
@property (nonatomic, readonly) NSString *today;

@end

CalendarViewModel.m我們大致這樣實作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@implementation PersonViewModel

- (instancetype)initWithCalendar:(Calendar *)calendar
{
  self = [super init];
    if (!self) return nil;
    
    _calendar = calendar;
    
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyyMMdd";
  NSString *date = [[dateFormatter stringFromDate:today] capitalizedString];
  
  return self;
}

@end

現在我們已經把資料轉換邏輯放到View Model裡面了,這時候我們table view controller就會非常輕量

1
2
3
4
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  [cell.todayLabel     setText:viewModel.today];
}

這樣一來並沒有改動太多架構,但透過我們把資料產生邏輯從Controller抽出來,獨立放到View Model,很明顯看到程式可維護性提高許多,整個架構耦合性降低更易於測試除錯修改。

And then …資料的更新與VIEW的刷新

整個流程是由ViewModel要發現source資料變化了,更新自己的property,接著通知Contorller根據ViewModel做更新UI的動作。這個通知學問就大了,可以有很多種方法。

很明顯我們可以只要修改ViewModel就指定Controller做刷新的動作,更大範圍來說這可以用KVO來時做追蹤View Model裡面的直有無變化來做畫面的更新。但這裡推薦最近發現的框架ReactiveCocoa,這個框架也是用來做數值追蹤,但本質上與之前的KVO, NSNotificationCenter都是截然不同的東西,我們在後續文章再來討論。

為何又開始寫文章?

| Comments

image

比履歷強多了

寫blog真的是很好推薦自己的方式。當你寫履歷的時候如果可以丟出一個個人網站,你馬上就像坐上噴射機一樣把其他人甩在後面!網站上面有你長期對產業或專業的獨特見解,這比光看履歷表更加分。

因為履歷表有可能是騙人的,大量美化的!但一個長期經營的部落格不僅可以快速令人信服你是某方面的專家,是別人想要的人才,也可以證明你是一個對此有熱情而且具備耐信與毅力等特質的人才,因為長期寫這些真得不容易。以上都是討喜而且履歷表線不出的特質。

少數可以累積的資產

好比複利,寫文章是你少數可以累積的資產,你花在這上面的時間是不會白費,久了你就可以端出別人拿不出來的好東西,你專業有深度的blog,這是你的絕對壓倒性優勢,因為這需要時間累積。

我很尊敬的謝老師說過:

時間是你最好的朋友。

不打烊廣告與找到志同道合好朋友

當你寫出有用的文章時,那些文章就像24小時不停放送的廣告,一直在幫你對外結緣。

在這個小眾化的時代,每個人都透過google去找尋自己有興趣的事物,而你的文章將可以媒合你與那些跟你志同道合的朋友。

強迫自己吸收新知

還有一點,如果一段時間你寫不出文章,那要麻你真的很忙,就像創業中的CEO,不然就是你的腦袋長時間沒有填入有用的知識,沒有新的觀念去衝擊既有知識。這能強迫你去取得有用的知識。

訓練口語表達

最後寫文章的好處在於整理思考。寫文章之所以比動嘴巴累是在於文章需要結構,需要起承轉合,需要腦袋思考反芻之後想辦法讓人易於理解。長期寫下來對於文字表達絕對具有巨大幫助。

對於口頭表達是否有幫助?絕對有!很多人會苦惱也時候就是表達不出自己的意思給別人,自己講得很高興但別人完全不理解。這中間差別就是你有沒有思考你到底要講什麼。任何觀點如果你寫成文章,你就可以通篇先在腦內整理一遍,你會知道重點,而當你之後用口頭跟別人講述,你自然而然可以吸引到聽者,並清楚表達你想講的事情。

對於Developer

如果你剛好是寫程式的,我想你真的要去好好去架一個blog並寫文章。你可以累積100篇你的解bug心得,技術新知,工作雜談。用LAMP或者Github網頁託管讓你免成本就有穩定page。有了平時準備,找工作時必然無往不利。有這麼豐富的參考資料證明你走過哪些路,還需要面試嗎?這跟現在很流行coder履歷要附上github帳號是一樣的道理,就是要看你平時做過哪些事情不是嗎?

我目前實在找不出經營一個自己的blog,持續寫有用的文章有任何壞處。 如果有,可以留言分享你的看法。

小技術大問題—救小狗Pivot到省百億

| Comments

image

一種解決問題的作法套用在不同的情境上,產生的效益就可能相差數萬倍。我們專題一開始看到路邊有受傷流浪狗兒,如果冷眼旁觀實在是不忍心,但第一個你不知道該找誰幫忙?找市立收容所?電話是幾號?更別提還要花許多時間在通報,通報了也可能只是安樂死。第二個可以找當地流浪動物協會,但一般人根本不會知道有哪些協會可以幫忙!現代人很忙碌,很費工夫的事實在是心有餘而力不足。所以我們想利用智慧型手機結合當地相關協會標準化通報流程,就能快速定外拍照上傳通報一次搞定,解決通報麻煩的問題,也就是流浪動物通報系統。

但找到問題並想方法解決每個人都會,但重點是找到的問題到底有多重要?好比上面的例子,一個人一年當中有多少機會碰到一隻需要救援的流浪狗,又有多少可能你真的會想要通報而身邊剛好帶著智慧型手機又知道我們的程式?這樣算下來我們當初設想的使用情境幾乎根本不會發生,所以其實是沒有解決到任何人的問題,效益等於零。

但當時我們整個通報系統都做出來了,但是卻因為效益等於零被迫重新想一個。但最寶貴的資源就是時間,豈容你從頭開始再試。以前實驗室老師有一句話說得好:「跌倒了先別急著站起來,看看地上有沒有東西可以撿起來」。所以只能在既有的系統上想一個新的應用,試著去提高帶給別人的效益—Pivot。於是流浪貓狗通報系統就搖身一變改成雲端路平專案通報系統。

Pivot的重點就是試著在不打掉根基的情況下,試著轉個情境找出新效益,而提高效益從問題面著手。路不有多嚴重?每年造成上百人傷亡、相關國賠高達上億,而每年花好幾百億就是改善不了,納稅人的錢都不知道被A到哪裡去,於上把通報系統應用在這麼大的問題上,帶來的效益就很可觀,畢竟這關乎到全用路人的權益。問題夠大也是後來全國專題競賽此系統能脫穎而出的關鍵。從來技術方法就不是重點,重點要有狼心、問題問大、問的讓人心有戚戚焉。

我們從舊有的方式去發現問題。傳統上人工報案曠日廢時又麻煩,就利用時下流行的智慧型手機標準化整個通報流程來解決,接著將資料上傳到我們在東京AWS的雲端伺服器做資料彙整。而常有部會首長要靠報紙才知道某個地方發生哪些問題,就彙整資料利用商業智慧的概念結合Google Map在上面標註圖案,首長透過視覺化圖表一眼就能了解全貌。而最重要的莫過於多年來花大錢路始終修不好,我們就把歷年資料全部公開,結合Facebook讓大家針對你不爽的事件來按讚分享,根據這些民怨做成熱門旁行榜,讓記者、議員來挖他們感興趣的資料,現在很多網友都利用這樣的模式來串連社群的力量幫自己來發聲,共同來監督公共工程。

路不平問題關乎到上百條人命、上千億的金錢,就算解決方法很爛效益只有5%,算一算還是5條人命50億,怎樣都打死一票小問題的最大效益。

一切都要回到『你到底要解決什麼問題?』

你要解決的問題很大很嚴重,別人根本就不會關心你用了什麼技術。悠游卡解決了你我不必每天辛苦找零錢的問題,但有人關心它使用的技術叫NFC嗎?除非你今天根本沒有解決別人真正關心的問題,才會需要拿絢麗的技術來拼命說來班門弄斧。所以一開始就選擇大問題去想方法,不要系統開發出來才發現沒人在意。

客觀簡報的困難

| Comments

image

我曾經待在一個瘋狂報名比賽,講究技術的硬派實驗室裡,我們報的比賽都是如微電腦、嵌入式這樣非常硬派的技術比賽,幾百坪的空間通常都很樸素,一些簡單的標語旗幟就差不多了。但是,裡面每個評審可都是相關領域中專家中的專家,我們做的題目大概用了領域內的哪些高階技術,多新穎、多困難、要花多少時間、多努力大概你稍微解釋一下彼此都能馬上心領神會。所以報告的流程就是帶一下要解決的問題,接下來就直接DEMO實際系統,什麼前言、動機、問題嚴重性越少越好,有的評審乾脆會叫你跳過把時間留給實際DEMO。這種我稱之為工學院比賽。

就像期末教授叫你上台報告這學期學到了什麼一樣,大家在同個領域差不多的背景知識下,大概都能很快了解你在講什麼。所以把所用的厲害技術說出來,DEMO系統不要出大問題,剩下就看評審對你的技術還有DEMO給幾分了。我其實建議所有人都要參加過這種比賽練底子,有了某方面底子說話自然比較不怕,提昇台風很明顯。

還有另一種比賽叫商管型,會場佈置像金馬獎,參賽隊伍如嘉年華,甚至現場還有live小組直播比賽狀況。這種比賽就是大,面對所有大眾,所以邀請的評審來自四面八方,政府官員你不知道是那個部門的、CEO你不知道是那家公司的、教授你不知道是鑽研哪個領域的,每個人的知識背景都不一樣,所以你要怎麼聊技術?你會跟一個阿嬤努力解釋你用了什麼技術嗎?還是你會努力把這個產品跟她的孫子產生連結?這就是很多專業型團隊一跨到商管型比賽時常會感到挫敗的盲點。

常常硬底子團隊自己埋著頭幹,技術一直講,別人狀況外也不知道。等到你回過頭來發現怎麼你講的跟評審想的完全是兩碼子事,問題才瞬間爆發開來。這時就會產生參賽者覺得莫名其妙,評審超難溝通,分數打得超沒依據,我愁眉苦脸,千里馬沒有伯樂,這些努力和辛酸沒人了解,公道在哪裡。

當你報告的時候評審在想的事情永遠都跟你想的事情不一樣。你在學校演練的講稿都是你自己想講的,都不是評審想聽的。你一定要多找老師反覆報告給他們聽,然後趕快根據回饋修正,這種顧客開發方式才會在客觀上抓住重(賣)點。絕對避免出去比賽前一天才把第一版的講稿生出來,然後感覺很充實很滿意,結果出去比賽才發現怎麼觀眾反映都在意料之外。

想辦法把你的題目推銷給一般大眾,你要說服他們真的很難。不要花了一堆時間在講別人不懂的技術,然後看到自己的DEMO系統畫面就覺得很爽大功告成。重點真的不在你多寫了幾個小功能,因為別人真的不想知道「你」做了什麼,簡報的重點是讓「評審」有興趣,重點是這個系統跟他到底有什麼關係?不管是拿問題嚴重性來威嚇評審,拿效益比如你有跟哪幾個有名大咖合作來說服評審,或是拿流程圖外加講故事講到他們心有戚戚焉,這樣子反覆的透過他們的生活經驗講他們聽的懂的話,你的終極目標拿高分才有可能實現。沒有連結就結束的簡報就好像是跟評審說:我不想知道你到底懂了沒,反正我做了出來而且很讚,請給分。

你確定寫程式跟製造業不一樣?

| Comments

image

台灣從過去製造業的思維延伸很喜歡做/教一件事,就是coustom development顧客開發的相反叫product development產品開發。而事實上創意特別是網路,一定是顧客開發,因為沒有什麼產品好做阿!我們又沒有什麼很厲害的晶片,很神奇的電路什麼的,引用一位網路業的前輩大師在他的FB上寫的這段話:

台灣培養出一堆癡狂幫別人做產品的公司和人才,做完交差就認為大功告成。國外公司則是拼命想把做產品的時間縮短,花大量時間資源在做行銷、銷售和品牌。格局和野心,決定了這世界誰主宰,誰血汗。Alex,EZTABLE Co-Founder&CEO

舉個例子來講,所有人都在講說鴻海多厲害多厲害,鴻海很偉大,搶下訂單幫apple做出一隻隻iphone很了不起,tpk 宸鴻做出面板超屌,然後每天台灣人就在自爽台灣之光台灣之光。我問大家,請問做一隻iphone比較難還是今年要賣出8000萬隻iphpne比較難?

當然是賣阿!

所以這個毛利的分配是很正常很合理的,當台灣一天到晚哀號iphone毛利台灣只分到0.6%~0.7%,因為做的價值就只有到那裡阿,你看賈伯斯還要上台講個發表會演說,用那麼漂亮的廣告,還有那麼棒的文宣,還要在世界各地蓋都可以當旅遊景點的apple store!那些東西很難耶!那比待在實驗室,不用接觸消費者,每天關在實驗室做事情寫code這個最簡單。

只是這個東西為什麼最簡單,因為他只是要勞力去換回來,勞力還有肝!可是我跟你講肝跟勞力就是最廉價的東西,誰沒有勞力誰沒有肝誰不會砸?腦袋和知識產業才是最難的。要消費者買你的帳要想多久?你的壓力多大?所以為什麼你看到台灣的工程師常常都是乾乾癟癟瘦瘦的,因為肝不好麻,為什麼那些apple的工程師(還有你常在國外網站電影上看到的工程師)每次來鴻海富士康巡場的時候每個都吃的肥肥的,可是都禿頭?

因為他們一天到晚都在想完蛋了賈伯斯要叫我賣8000萬隻,我去哪裡找來8000萬個人來買iphpne?所以這些壓力都在腦袋裡,他必須要靜下來想,這不只是做什麼事情的問題,他還要想怎樣來賣。可是台灣的我不用想,我就是做,別人交代什麼就做什麼就對了,趕快想,雖然是想可是就是想著怎麼把它做出來,做出來也不是你的東西,後續產出的價值也跟你無關,所以是做白工,又是浪費勞力,跟製造業差在哪裡?

在這個知識產業凌駕一切的時代上,所以我希望跟我一樣是7、8年級的,真的希望台灣脫離製造業思維,把自己從別人影子後面推出來。舉個例子,奇美面板一開廠就賠20億,那沒有意義阿,台灣有很多這種很奇怪的事,這代表說台灣真的需要走出來,我們需要把東西直接推出來面對消費者,而不是躲在後面。講難聽一點,就是要做鴻海,好歹談判的時候要在iphone後面要印個produced by foxconn吧,好歹做一點品牌吧!懂我意思嘛?

不要一天到晚幫人家做事,然後交差就覺得很了不起這樣,沒有用。幫別人代工未來都賺不到什麼錢。