sakaharaのブログ

アプリ開発に関する話や日々の出来事など

「ビジネスモデル・ジェネレーション ビジネスモデル設計書」を読んでみた

同僚に紹介されて読んでみました。

率直な感想を書きます。

そもそもビジネスモデルって何?という段階で読んだ私には中々頭に入ってこない内容でした・・・。 (本のサイズも横長で持ちにくい上、構成も変わっていて読みにくかった) また本書の内容もいきなりビジネスモデルキャンバスというフレームワークの説明から始まり、このフレームワークがなぜよいのか、特に記述がなかったのも理由かもしれません。 他の方法と比較しようもないのですが、もしかするとそもそもビジネスモデルを構築していく手法が全然確立されていないから、このビジネスモデルキャンバスが有効なのかも?と勝手に納得しています。 ただそれらを抜きにしてもチームでいっしょにビジネスモデルを考えるやり方としてはよさそうな印象でした。

そしてそんなに私にビジネスモデルの定義を本書は明確に書いてくれています。

ビジネスモデルとは、どのように価値を創造し、顧客に届けるかを論理的に記述したもの。

元々私はビジネスモデルというのはこれまでの成功事例のやり方をいくつかの似た方法に分類してまとめたものだと勝手に思っていました。 ですが既存のビジネスモデルを定期的に評価して調整していくことこそが重要だというが本書を通して分かります。

例えばP. 258のデルの例は非常に分かりやすいです。

デルは、受注生産の形態やオンラインでのダイレクト販売を導入することで、PC業界に波乱を起こしました。その成功によりデルは、長年にわたり業界のリーダーとして成長してきました。しかし、その破壊的なビジネスモデルを再考することに失敗しました。今では、業界の状況も変わってしまい、デルはコモディティ化してしまったPC市場で立ち往生するリスクを抱えています。

またビジネスキャンバスを使って既存のビジネスモデルを体系的に整理して説明してくれているので、自分たちのビジネスモデルを考える上でも参考になる部分も多く、純粋におもしろいです。

一度読んで終わりの書籍ではなく、何度も読み返しながら実際にためしていくのが一番よいと思います。

「アジャイル開発とスクラム 顧客・技術・経営をつなぐ協調的ソフトウェア開発マネジメント」を読んでみた

新たにアジャイル関連の書籍を入手したので読んでみました。

この書籍は経営層や管理職の方、またはアジャイル開発の導入を会社へ提案したい人が読むとよいのではという印象です。 特に第2部ではいくつか国内の事例を紹介しており、これからアジャイル開発を検討する方には参考になる部分が多そうです。 スクラムがどのようなものかについても触れていますが、具体的にスクラムでの開発のやり方を知りたい方は以前の書評で紹介した「SCRUM BOOT CAMP THE BOOK」がおすすめです。

印象に残った箇所にP.54のコラムで触れているウォータフォールの問題点があります。

このアプローチでは途中で計画外のよりよいやり方がみつかっても採用できない。すべてのよいアイディアは、プロジェクトの最初で計画する必要がある。

これは全ての要件を最初に固めてしまうのが前提のウォーターフォールでは、後からの仕様変更に柔軟に対応しにくく、開発者側からすると仕様変更は悪みたいなことになりがちです。

しかし、ウォーターフォールが極めて論理的であるため、「もっと上手にやっていたら、うまくいったはずだ。もっと文書化し、変更を最小限に抑えれば、すべてもっとスムーズにいくはずだ」と思い込んでしまう。残念ながら、多くのチームでは逆の結果になる。しっかり管理すればするほど、さらに悪い結果になるのだ。

これは正にその通りだと思います。しっかりやろうとすればするほど悪循環になりやすく、変更を最小限に抑えようとして本当に必要なものが作れなくなるなど、本末転倒な結果にもなったりします。 ウォータフォールはよくないとまでは思いませんが、最初に全てを決めようとするプロセスは特に技術革新の激しいソフトウェア開発においては適応するのが難しくなってきていると言えます。

P.129のリクルートの事例の部分も的確に問題点を捉えています。

SWATでは、「持ち帰りは禁句」という原則を打ち出した。従来のように会議の席上で100%の確約を要求するのをやめ、「可能性80%ならOKと答えてもよい。その代わり、持ち帰って検討は禁句」と関係者全員に理解をもとめたのだ。

全てを最初に決めようとするとあとから技術的に難しいものや、見積もりが思った以上にかかることが後から発覚しても「あの時そういったじゃないか!」と揉める原因になることも多いです。 そのため100%の確認をするために一旦持ち帰らせてもらうことは私もよくありました。ですがその場で決定できないため、スピード感が落ちることはどうしても止む終えない状態になりました。 それを解決するたのルールとしてはとてもよいと思いますが、この80%と調整の部分はさじ加減が難しいとも思います。

そして一番印象に残ったのはP.241のこの部分です。

このことで、筆者はアジャイルを目的ではなく手段だと考えるようになったし、また、「アジャイルウォーターフォール」とか、「プログラマ対管理者」といった敵・味方の味方ではなく「現場をよくしたい」という気持ちで活動することが大切だと実感した。

アジャイルを意識するばかりアジャイルでやることが目的になってしまうというのは本末転倒です。 常に手段が目的になってしまわないよう気をつけないといけません。 また開発が人ありきで進む以上、敵・味方とか関係なく常によくして行こうという気持ちをメンバー全員が持てるようにすることが一番重要だと改めて認識しました。

最後にアジャイルウォーターフォールとの比較でアジャイルのメリットを知りたい方にもおすすめです。

「強いチームはオフィスを捨てる」を読んでリモートワークのメリット/デメリットについて考えてみた

私は京都で働くようになるまでは元々広島で仕事をしていたので、以前からリモートワークに興味がありました。 広島に居ながら東京の会社に就職して仕事ができたらいいなぁーと漠然と思っていた時期もあります。 ただ実際にリモートワークをやるにしても正直不安な部分も多いし、難しいだろうなぁという程度で実現するまでには至りませんでした。

まだ実践できていない段階ではありますが、「強いチームはオフィスを捨てる」を読んだ感想も踏まえメリット/デメリットを書く事で、リモートワークを検討中の方に参考になる事があれば幸いです。

まず本書を読んだ中から思いつく限りメリットを書き出してみました。

リモートワークのメリット

  • 通勤時間の短縮、自宅なら通勤が必要なくなるので時間を節約できる
  • 9時5時などの時間の制約から解放される
  • 東京など仕事の集中している地域に住む必要がなくなるので、住む場所は自由に選べる
  • オフィス面積の節約など経費削減に貢献、極端な話オフィスがなくても大丈夫
  • 会議や雑談を減らしやすいので作業に集中しやすい
  • 対面での影響力が減る代わりに、成果での評価がしやすくなる(謙虚だけど仕事は着実にこなす人によいかも)
  • 優秀な人間を場所の制約なく採用できる

さらっとメリットを書きましたが、場所の制約がなくなるのと時間を自由に使える部分が増えるというのは、人によってものすごく人生を豊かにできる可能性があります。

リモートワークのデメリット

  • 会社や同僚の協力がないとリモートワークをしている人が孤立しやすい(島流し状態?)
  • 部下が見張っていないと仕事をしないのではという考えが根本にあると成立しない
  • 働かなくなる人よりもむしろ働き過ぎになる人が多い
  • 文章力が無い人がやるのは難しい
  • 同僚との会話が減る分、仕事の成果に注目が集まるので成果を出せる人でないと難しい?(むしろメリットかも)

こうしてデメリットをあげていくと見える成果を出せる人でないとリモートワークはやりにくい印象です。 また周りが一緒にリモートワークを成功させようというスタンスでのぞまないとリモートワークをしている人が孤立してしまう可能性が高いです。 安易な考えでリモートワークを取り入れてしまうと失敗するだろうなというのが率直な感想です。

また本書では触れてませんがセキュリティ上の理由から情報を外に出せない会社では成立しにくいです。 昨今セキュリティ関連の事件が明るみに出ているので、リモートワークを難しくする一因になっているかもしれません。

デメリットだけみると難しいのかな?と思われる方もいると思いますが、本書には問題点を解決する方法もふんだんに書いてあるので変に心配はしない方がいいです。 セキュリティに関しても対策をきっちり行っていれば問題ないはずです。 孤立する問題に関しては同僚もそうですが、経営者や上司がリモートワークを実際に体験することで何をサポートするべきか分かりやすくなります。 部下を見張る必要など実際はほとんどなく、仕事をしているかどうかの問題は目標をはっきりさせてその成果をちゃんと精査することで解決できます。 毎日顔を会わせることがないために孤独に落ち入ってしまう人もいるかもしれませんが、それは家族がいる方ならその可能性はあまりないでしょうし、家族がいない人は地元の交流イベントやなどに参加することで人との交流をもつなどできることはたくさんあります。

リモートワーク礼讃というわけではありませんが、社員の幸福、社員一人一人の成果についてきちんと考えてみるなら導入するメリットは計り知れないです。 優秀な人を雇うのに近くの人だけという制約もなくなりますから。

また本書で紹介しているリモートワークを支援するツールもそうですが、最近はかなりそういったツールが増えてきているので、いいものがあればすぐ導入して日頃から業務で使う文化があるとリモートワークが成功しやすいと思いました。 それにいきなり遠く離れたところでやり始めるのではなく、オフィスに通勤できる圏内に住んで、 週に2、3日とか午前中だけ出社するなど、段階的な導入がより現実的な気がします。

最後にリモートワークを実際にしている人の情報ほど役に立つものはないと思うので、そういった方のブログのリンクを掲載しておきます。

アジャイル開発をより良く知るために「SCRUM BOOT CAMP THE BOOK」を読んでみた

アジャイル開発の手法の一つであるスクラムについて知るために読んでみました。

本の内容はマンガ付きでとても分かりやすくスクラムについて説明してあり、2時間程度でさっと読める内容でした。 短時間で読めるからといって内容がないわけでは無く、実際にプロジェクトで起きそうな問題をスクラムマスターの主人公とプロダクトオーナー、開発チームが解決していくストーリーは実用的でありスクラムのメリットを十分に知ることができるものでした。

個人的な感想としてはやはりスクラムは予算や納期の決まった受託開発より、ウェブサービススマートフォンアプリ開発に向いているなぁという印象です。 逆にいえばウェブサービスアプリ開発をウォータフォールでやってしまうとうまくいかないだろうなと改めて思いました。

例えばベロシティはスプリント毎に終わらせられるポイント数であり、ある程度プロジェクトを進めることによって見えてくる数値なので、予算・納期を前もって決めないといけない場合、ベロシティが分からないためかなり見積もりがつらくなってしまいます。 受託開発で採用する場合、納品のない受託開発がベストなのかなぁーと思います。(このフレーズ最近よく聞きます)

本書を読んだ中で特に印象に残ったフレーズとして、「そのロールで求められていることに一生懸命とりくんでくれるかどうかだ」という箇所があります。 これってかなり根本的な話で、スクラムやそれ以外の手法関係なくちゃんと熱意をもってとりくまないと何やってもうまくいかないし、ちゃんと取り組んでくれる人達が集まればそれなりにうまく回るととも言えます。 ただスクラムの場合、どんな人が集まってもどこかのポジションには当てはまる人がいるはずで、プロジェクトを動かしながら手探りで進められる部分もあるので他の手法より成功率は高くなるかもと思いました。

それからもう一つ「Scrumでは、開発チームは自己組織化されていて、機能横断的であることが求められている」も印象に残っています。 これができるメンバーが揃っていればスクラムだろうと何だろうとうまく回るの当たり前だろうなーと思いましたw ただスクラムの手法をちゃんと取り入れることができれば自己組織化していくことも可能なので結局やり方しだいですかね。

あと個人的に痛かったのは「それぐらいはできるよね!?」というところで実際の作業に関係ない人の意見は参考意見程度にしておかないといけないというところです。 実際に作業をする人やチームの意見でないと現場のさまざまな情報をもとにきちんとした判断はできないので、作業に関係無い人に何を言われようと自分やチームのメンバーがちゃんと約束をして取り組んでいくことで責任感もうまれ、それがよい結果につながると改めて認識しました。 周りに振り回されないようにしたいものです。

最後に言えることは、どんな手法を取り入れようとチームメンバーに対する信頼が無い場合や、失敗の責任を個人に押し付けるような組織では何やってもうまくいきません。 特にスクラムは自己組織化されていることが前提であるならばそれはかなり重要な要素です。 そういった信頼関係を築きつつスクラムを試してみるのが一番よいのかなと思いました。

この本はプロジェクトで困った時などにヒントになることがたくさんあるので、そういった時などに見返してみるとまた得るものがあって更によいのでオススメです。

Swiftでウィジェットを作ってみた [iOS]

概要

iOS8でSwiftでウィジェットを作る方法をさらっと書きました。 環境はXcode6-Beta3を使ってます。 アプリから入力したテキストをウィジェットに表示するだけのシンプルなものです。

手順

まずプロジェクトを作成します。ここではSingle Web Applicationを選択しました。(プロジェクト名:TodayExtensionExample)

Today Extensionを使用するため新規にターゲットでToday Extensionを作成します。(ターゲット名:TodayExtension)

アプリとウィジェットでデータを共有するために今回はApp Groupを使用します。

プロジェクトのTargets->CapabilitiesからApp Groupを有効にしてGroup IDを設定します。 これはアプリとウィジェットのターゲット両方に設定してください。 ここでは"group.TodayExtensionSample"をキーとして使用します。

下準備ができたので今度は画面を作っていきます。まずはアプリの入力画面ですが、UITextFieldUIButtonを一つ配置するシンプルなものを想定しています。

UITextFieldのプロパティを宣言しておきます

@IBOutlet var commentTextField: UITextField

Saveボタンをタップした際のイベントです。ここでNSUserDefaultsを使ってデータを保存します。Group IDを指定することでウィジェットとデータが共有できます。

@IBAction func saveCommentAction(sender: AnyObject) {
    let sharedDefaults:NSUserDefaults = NSUserDefaults(suiteName: "group.TodayExtensionSample")

    sharedDefaults.setObject(commentTextField.text, forKey: "textValue")
    sharedDefaults.synchronize()
}

次にウィジェット側のUIを作ります。アプリ側で入力したテキストをラベルに表示するのでUILabelを配置します。

次にUILabelのプロパティを宣言します。

@IBOutlet var textLabel: UILabel

初期化時にNSUserDefaultsDidChangeNotificationで変更を検知してuserDefaultsDidChangeメソッドを呼び出すようにします

init(coder aDecoder: NSCoder!) {
    super.init(coder: aDecoder)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "userDefaultsDidChange:",
        name: NSUserDefaultsDidChangeNotification, object: nil)
}

ウィジェットを表示するための追加の処理です

override func viewDidLoad() {
    super.viewDidLoad()
    // Auto Layoutを使用しない場合、preferredContentSizeで高さを指定する
    preferredContentSize = CGSizeMake(320, 50)
    // テキスト表示
    updateTextLabel()
}

アプリ側でテキストが変更されたらウィジェットに反映します

func userDefaultsDidChange(notification: NSNotification) {
    updateTextLabel()
}

アプリ側で保存したテキストを取得してラベルに表示します

func updateTextLabel() {
    let defaults:NSUserDefaults = NSUserDefaults(suiteName: "group.TodayExtensionSample")
    textLabel.text = defaults.stringForKey("textValue")
}

これでプログラムを実行してアプリでテキストを保存するとウィジェットに入力したテキストを表示することができます。

まとめ

手順自体はシンプルなのですが、Xcode6の不具合もあるのか表示するまでにいろいろ問題がありました。 それらについてまとめてあるサイトもあるので参考にしてください。

http://qiita.com/wao9@github/items/d983811ac48b71ffe072

iOSでFacebookのログイン方法について整理してみた

久しぶりにiOS向けFacebook SDKを使う機会があったのですが、ログイン方法が本当に多様になってたのでざっくり整理しました。 種類が増えててドキュメントちゃんと見ないと混乱します・・・。 ということで内容の整理兼ねてのメモとして書いています。

ざっくり整理してるだけなのでもっと詳細を知りたい方は公式ドキュメントを見てください。

https://developers.facebook.com/docs/facebook-login/ios/v2.0

  • FBLoginView

これは知らなくて驚いたのですが、専用のログインボタンができたようです。 ドキュメント見る限りかなり簡単に使えそうです。

  • Facebookネイティブアプリ・ログインダイアログ

これはFacebookアプリをインストールしている場合に使えます。 アプリにログイン済みであれば認証は必要ないのでユーザーの負荷は少ない言えます。 欠点としてはiOS6以上でアプリをインストール済みでないと使えないことです。

  • iOSログインダイアログ

iOS6から追加されたOSに組み込まれたFacebookのログイン形式です。 すでにログイン済であればログインフローをユーザーが意識する必要がないので一番理想的な方法だと思います。 欠点としてはユーザーがログインしていない場合、設定画面からログインしてもらうよう誘導する必要があります。

  • Facebookネイティブアプリ・Webベースログインダイアログ

古いバージョンのFacebookアプリをインストールしている場合に使えます。 ネイティブアプリのログイン画面より遅いの欠点です。

  • モバイルSafari・ログインダイアログ

Facebookネイティブアプリをインストールしていない場合に使えます。 欠点としてSafariへの切替が発生や、ネイティブアプリと比較して速度が遅い点などがあげられます。

  • WebViewログインダイアログ

ログインダイアログを表示するコードを毎回直接書いて表示します。 ログインフローで毎回ユーザーがユーザーID、パスワードを入力する必要があります。 また欠点としてネイティブアプリと比較して速度が遅い点やがあげられます。

ログインするためのサンプルでも書こうと思いましたが、すでによいものがあるのでそちらを 見た方が早いです。

http://github.com/fbsamples/ios-howtos

とこんな感じでログイン一つとっても多種多様になってました。 ログインするプロセスというのはユーザーにとってとてもストレスがかかるところなので、 負担をなるべくかけないようにするための努力の後が伺えます。 しかし使う側はなんだか混乱してしまいますが・・・ある程度はSDKが自動で制御してくれるのでそれらを踏まえて使うのがよいです。

Swiftを使ったAFNetworking 2.0 のまとめ [iOS]

概要

以前書いた記事を勉強がてらSwiftに置き換えてみました。 習うより慣れろ!と言う言葉通り実際触ってみるのがやはり使えるようになるための一番の近道です。

AFNetworking 2.0以降を使うには下記が必須要件となっていますので導入前に確認してください。

大きな変更点としてドキュメントにあるようにiOS7以降のサポートのみでよければAFHTTPSessionManagerのサブクラスを作成して実装することが推奨されています。 iOS6やそれ以前のバージョンをサポートする場合の選択肢としてAFHTTPRequestOperationManagerが用意されています。

前回のまとめ同様に主にAFHTTPRequestOperationManagerの使い方について触れておきます。

使い方

Objective-Cを使う際と同様にインストールもCocoaPodsで簡単に導入できますので、下記Podfileをプロジェクトのルート直下に作成してインストールしましょう。

platform :ios, '7.0'
pod "AFNetworking", "~> 2.0"

GETで使う場合

let manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFHTTPResponseSerializer()
manager.GET("http://hoge/sample.json", parameters: nil,
    success: { (operation: AFHTTPRequestOperation!, responseObject:AnyObject!) in
        println("response: \(responseObject)")
    }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
        println("error: \(error)")
    })

POSTでパラメータを設定する場合

let manager = AFHTTPRequestOperationManager()
var param:Dictionary<String, String> = ["param1" : "value1", "param2" : "value2"]
manager.POST("http://hoge/sample.json", parameters: param,
    success: { (operation: AFHTTPRequestOperation!, responseObject:AnyObject!) in
        println("response: \(responseObject)")
    }, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
        println("Error: \(error)")
    })

レスポンスがJSONではない場合

let manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFXMLParserResponseSerializer()

としてAFHTTPResponseSerializerをセットしておきましょう。 デフォルトがAFJSONResponseSerializerのためJSONのパースエラーになります。

レスポンスがXMLの場合

let manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFXMLParserResponseSerializer() as AFHTTPResponseSerializer
// 許可するContentTypeの設定が必要
manager.responseSerializer.acceptableContentTypes = NSSet(object: "application/rss+xml")

結果のresponseObjectがNSXMLParserなので自前でパースする必要があります。 パースするSerializerを自前で用意してもよいでしょう。

リクエストパラメータをJSONにしたい場合

let manager = AFHTTPRequestOperationManager()
manager.requestSerializer = AFJSONRequestSerializer()

上記ようにAFJSONRequestSerializerを設定します。

通信ログについて

通信の詳細なログが見たい時はAFNetworkActivityLoggerを別途インストールするとリクエストヘッダー、レスポンスヘッダーもログ出力してくれます。

platform :ios, '7.0'
pod "AFNetworking", "~> 2.0"
pod "AFNetworkActivityLogger", "~> 2.0"

PodfileにAFNetworkActivityLoggerを追加してインストールします。

AppDelegate.swift'の'application:didFinishLaunchingWithOptions::にログを開始する処理を記述します。

AFNetworkActivityLogger.sharedLogger().startLogging()

ログレベルをAFLoggerLevelDebugにすればリクエストヘッダー、レスポンスヘッダーを含む通信のやりとりをログに出力できます。

AFNetworkActivityLogger.sharedLogger().level = .AFLoggerLevelDebug

キャッシュポリシー、タイムアウトについて

AFHTTPRequestOperationManagerを使用せずAFHTTPRequestOperationを直接使用する場合はcachePolicyの設定ができます。

let URL = NSURL.URLWithString("http://hoge/sample.json")
let request = NSURLRequest(URL: URL, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval:60.0)
let operation = AFHTTPRequestOperation(request: request)
operation.responseSerializer = AFJSONResponseSerializer()
operation.setCompletionBlockWithSuccess({ (operation: AFHTTPRequestOperation!, responseObject:AnyObject!) in
    println("response: \(responseObject)")
}, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
    println("Error: \(error)")
})

operation.start()

セキュリティポリシー

テスト環境などでSSL通信をする際にオレオレ証明書(自己署名証明書)を使っている場合は、AFHTTPRequestOperationManagerオレオレ証明書を許可する設定を行うことで通信できます。

let manager = AFHTTPRequestOperationManager()
manager.securityPolicy.allowInvalidCertificates = true
// 以降は通常通りAFHTTPRequestOperationManagerを使って通信を行う

まとめ

NSURLSessionの登場によって今後はNSURLConnectionがベースとなっているAFHTTPRequestOperationManagerではなくAFHTTPSessionManagerが主流になるのでそちらについても書きたいと思ったのですが時間の都合上、別の機会に書くことにします。

Swiftに書き換えた印象として、Swiftはスクリプト言語の経験がある方ならすんなり入れるはずです。 Objective-CのBlocks構文などとても書きづらく辛さしかなかったのですが、Swiftにシフトすればそんな問題からも解放されるし、いいこと尽くめではないかと思います。 もう少しSwiftのノウハウがたまってからでもよいかもしれませんが、個人的には新規アプリはSwiftで書いてしまう方が開発効率上がってよいと思いました。