株主優待を迷わずご利用いただくために気をつけたこと

こんにちは。会員事業部の高田です。

クックパッドでは、昨年に続き今年も株主優待としてプレミアムサービス1年分クーポンを配布しました。

株主の方々は、普段クックパッドを使っているユーザー層より年齢層が高く、インターネットに慣れていない方も多いと想定されたため、迷わずご利用いただけるよう気をつけました。今回はこのような事情から気をつけたことについて、昨年の事例を元に書きます。

一番最初にクーポンコードを入力してもらう

f:id:satoship:20160411144737p:plain:w600

プレミアムサービス1年分クーポンを利用するには、クックパッドにログインしている必要があります。多くのクックパッドのユーザーはログインせずに使っていることと、前述の想定から、株主の方々もログインしていない可能性が高いと考えました。

そこで、ログイン(またはユーザー登録)→クーポン入力という流れにすると、ログインしただけで離脱してしまったり、ログインした後に迷ってしまったりするのではないかと考え、一番最初にクーポンを入力してもらうことにしました。クーポン入力後、ログインしていないユーザーにはログインやユーザー登録の案内を表示し、ログインしているユーザーにはクーポンご利用画面を表示しました(以下のスクリーンショットを参照)。

[ログインやユーザー登録の案内] f:id:satoship:20160411144755p:plain:w600

[クーポンご利用画面] f:id:satoship:20160411144940p:plain:w600

ユーザー登録後にクーポン利用画面へのリンクを表示する

f:id:satoship:20160411145005p:plain

ユーザー登録後にどこでクーポンを利用すればいいのか迷ってしまうのを避けるために、ユーザー登録後の画面でクーポン利用画面に戻るリンクを表示するようにしました。

これは、前述の通り最初にクーポンコードの入力をしてもらっているため、Cookie の値などから、クーポンを利用しようとしているユーザーを判定することで表示しました。

「株主優待」で検索するとリダイレクトするようにする

配布したクーポンには「株主優待ご案内ページ」として URL と QR コードが印刷されていますが、うまく辿りつけずに問い合わせがくるかもしれません。また、サポートスタッフがなんらかの説明をする際に「株主優待ご案内ページ」を表示してもらいたいことがあるかもしれません。

そこでクックパッド内で「株主優待」と検索すると「株主優待ご案内ページ」が表示されるようにしました。

まとめ

今回は、プレミアムサービス1年分クーポンのシステムを開発する際に、迷わず利用できるように気をつけたことについて書きました。

はじめての試みだったため、明確な効果をお伝えすることはできませんが、開発チームの予想を上回る株主の方にご利用いただくことができました。また、問い合わせの件数も予想より少なく無事に利用期間を終えることができました。

サポートスタッフからは、実際のお問い合わせの際には、クックパッドのトップページを開いている場合が多かったため、「株主優待」と検索するよう案内できるのは便利だったというフィードバックもありました。

どの事例もささいなことですが、ディレクターやサポートスタッフや開発者がこれなら迷いにくく、サポートしやすいだろうという案を出し合って決めました。参考になることがあれば幸いです。

Try! Swiftで感じた将来

こんにちは。広告事業部のモバイルエンジニアパヴェウ @RusinPaw です。

先日、3月に東京で開催されたtry! Swiftカンファレンスに行ってきました。開催者のおかげで世界中の様々な優秀なスピーカーが発表してくれました。発表内容はSwiftに留まらずiOSフレームワーク(CoreData、CoreAnimation、HomeKit)やテスティング、ユーザビリティ、コードリーダビリティなど、様々でした。

Swiftとは

Swiftとは2014年のWWDCでAppleが公開し、プログラマーコミュニティを驚かせたプログラミング言語です。モダン、安全、書きやすくて読みやすい、既存のObjective-Cのコードベースに同時と使える言語と言われました。 実は「そんなにすごいのか」の議論はまだまだ続いています(SwiftとObjective-Cをミックスする時に困っている場合がある)が、Swiftは次第に多くのiOS開発者に支持されるようになり、新規プロジェクトのスタンダードになりました。2015年のWWDCではAppleはSwiftをオープンソースとして公開し、開発者たちを興奮させました。開発者は、言語開発とその進化の方向に関わることができるようになりました。

Swiftでコードを書くことのメリットは?

Swiftの公開後、「新規プログラミング言語が必要なの?」という疑問が多かったです。Objective-Cで作ってリリースして成功したアプリがたくさんあるからです。ところが、iOSの開発を始めようとする開発者にとってメッセージベースで複雑ワンマンチームの開発者がアプリをObjective-Cで書きリリースするのはかなり難しいです。クライアントとサーバーAPIを共にSwiftで書くことで、アイデアから最小構成の製品を作り上げることが簡単にできるようになると思います。

Objective-Cを書いてる経験者にとってもObjective-Cの複雑で冗長なシンタックスのコードを読んだり、管理したり、デバッグするのは時間がかかります。クックパッドのように長い間プロジェクトを開発し続ける会社の場合は、ソースコードは貴重な資源として扱うので、できるかぎり読みやすいコードを書くのは大事です。

Try! Swift

Try! Swiftの発表の内容は多岐にわたり、言語そのものに関する詳しい話もありました。それらから、Swiftとそのコミュニティが現在直面する大きな希望と挑戦を示すいくつかのメインテーマがみえてきました。

既存のオブジェクト指向プログラミングのフレームワークを使いながら関数型の機能とプロトコル指向機能を使える

Swift自体はマルチパラダイム言語ですが、既存のiOSフレームワークはすべてオブジェクト指向のパラダイムで作られていました。なのでオブジェクト指向の世界でSwiftの機能を使う方法について色々な話がでました:

  • 野中彩花氏は実践的 “Boundaries”コーディネートのパターンで内部クラスと外部のAPIを区別する方法について発表をしました。
  • Daniel Eggert氏は既存のObjective-CのCoreDataのAPIをプロトコルとエクステンションを使ってモダンなのSwiftのインターフェイスを作りました(Modern Core Data)。
  • Daniel H Steinberg氏はBlending Culturesでオブジェクト指向と関数型とプロトコルという3つの世界を一緒に合わせてそれぞれの特徴を使えることについて話しました。
  • Chris Eidhofのライブコーディングセッションでは view controllerからconfigurationオブジェクトとしてカスタム部分を抜きだし、複雑さを下げる方法が紹介されました。Swiftの関数は第一級オブジェクトなのでそういうconfigurationにカスタムロジックを入れることができます。この仕様を作ったら一つの複雑なview controllerではなくて汎用のview controllerとテストしやすい設定を分けることができます。

Cross-platformとオープンソースSwiftの流行り

Swiftのオープンソース化のおかげで一般のエンジニアはその新規言語の方向を決められます(Jesse Squires, Contributing to Open Source Swift)。LinuxでもSwiftの開発ができます。try! Swiftの発表には、サーバーサイドSwiftに関する発表(Soaring Swiftly - Server Side Swift - Caesar Wirth)、Linuxでの開発で起こる問題(Practical cross-platform - JP Simard)についての話もありました。今現在、一番不便なのはObjective-Cのダイナミックランタイム、そしてダイナミックランタイムで使えるキャストかGrand Central Dispatchがないことです。それでcross-platformを作るなら:

#if os(OSX)
    // ダイナミックランタイム機能を使う
#else // Linux
    // なんとかする
#endif

みたいなひどいコードが多くなります。

Swiftでモバイル以外の開発はまだまだなので必要なツールが少ないです。だからプログラミングしやすくできるようにツール、またはCIツールを開発する機会があります(池田翔 - Dive in Swift Ecosystem)。自分で新しいライブラリを立ち上げる(Creating a Swift Library by Jeff Hui)か、それとも他のエンジニアに便利なツールを作るか色々な貢献のチャンスがあります。

クックパッドでSwiftをtry!してますか?

現在、クックパッドの新規アプリはすべてSwiftで書いています:

しかし、メインの「クックパッド レシピ検索&スーパーのチラシアプリ」はほとんどObjective-Cで開発してます。Swiftで書いてるコードはPOCとして実装されたUITestです。

なぜかというと、アプリで使ってるCocoapodsというdependency managerを利用しているからです。CocoapodsとSwiftのターゲットのダイナミックライブラリをiOS8以後で一緒に使う可能です。iOS7でもターゲットのダイナミックライブラリビルドすることができますが、そのようなアプリはAppleの審査でリジェクトされてしまうでしょう。 クックパッドのアプリはまだiOS7をサポートしているので、Swift を利用するかどうか慎重に考えているところです。そのサポートが終了した際には以下の方法で既存のコードベース内のSwiftのソースコードの割合を増やしていこうとおもいます。

  • 新規クラスをSwiftで作ります。
  • 既存のObjective-CクラスにSwiftで作った新規メソッドを追加します。
  • Swiftのextensionを使って既存のObjective-CクラスにSwiftで作った新規メソッドを追加します:
@implementation ClassA

    - (void)methodA { ... }

    - (void)methodB { ... }

@end
extension ClasA {

    func methodC() {

        ...

    }

}

たとえ、我々のようにSwiftを利用できる場面が限定されていても、Swiftを勉強することで、安全で読み易いコードを書けるようになると思います。Swiftの特徴的な機能:

  • 継承よりインターフェイスを使う
  • オブジェクトのステート数を減らす
  • オブジェクトをイミュータブルに強制される

に従えばコードを理解したりデバッグしたりするのに使う時間を減らせると思います。来年のtry! Swiftが会議が楽しみです。そして来年のSwiftとSwift製ソフトウェアがどうなるか気になります。

開発の見積もりとスケジュール管理

こんにちは。会員事業部の丸山です。

エンジニアが開発を開始する時にはタスクの見積もりとスケジュールを作成行って、実装を進めていくと思います。 しかし1ヶ月を超えるような規模の開発をする場合、なかなか予定通りの期日に終わらなかったりすると思います。 そして大抵の場合、増える方向になりますよね。 今回はそういうことにならないために、私が気をつけていること・実践していることをいくつか紹介したいと思います。

見積もりとは

まずは「見積もり」とは何なのかを正しく理解したいと思います。 一般的には「見積もり」=「全タスクとその工数を洗い出す」というものだと思います。 しかしここで以下のことに気をつける必要があります。

見積もりとスケジュールとコミットメントは違う

見積もりとはあるタスクがどれだけの工数(規模)なのかを算出することです。 対して、スケジュールとはあるタスクがどれだけの工期(期間)なのかを算出することです。 この2つを混同してしまうと、正しく仕事をすすめることができません。 例えばタスクAの工数が8時間だったとしても、それを担当する人の稼働が実は1日に4時間しかない場合、工期は2日(16時間)となります。

次にコミットメントは最終的な予算・期間・品質をどういうバランスにするかを決めて、約束をすることです。 たとえば10個のタスクを見積もり、スケジュールを立てたところ、1人で3ヶ月かかることがわかりました。 この話を責任者にすると「2ヶ月で終わるようにしてくれ」という要望があり、見積もりをなんとか捻じ曲げてして、2ヶ月で終わるようにしました。

しかし、本来はコミットメントをどうするか?という話を責任者とする必要があります。 人的リソース(予算)を増やすのか、リリース日(期間)をもう少し遅らせられないか、機能(品質)を削ることができないかなどを話し合うべきです。 コミットメントが変わらないのに、見積もりやスケジュールは変更されません。 これを混同してしまうと、現場も責任者も両方不幸になってしまいます。

「見積もりをしてください」と言われたら

では「見積もりをしてください」と言われたらどうしたらよいのでしょうか? 見積もりを行うには大きく2つのステップがあります。

  1. 作るべきものをタスクに分解する
  2. タスクの規模を算出する

タスクに分解する

まずタスクに分解するステップですが、これは「タスクに分解する」と捉えるよりも「設計をする」と捉えたほうがよいと思います。 つまり見積もりをするときに一番初めに行うことは設計です。作るべきものを設計し、具体化しなければ正しくタスクに分解できません。 そしてこのことから分かるように、見積もりを正確にするには時間をかけるのではなく、より詳細な設計をすべきです。

ここで、一つ問題になるのがどこまで詳細な設計をすべきなのか?ということです。 これを定量化するのは難しいのですが、開発している対象によってだいたい似たパターンがあると思います。 例えばWebサービスを開発しているサービスエンジニアの場合「画面一覧/Controller/Model/View/テストコード/インテグレーションテスト/テーブルスキーマ/マスターデータ/ログ」などに分解することが多いと思います。 他にもインフラや開発基盤系のタスクを分解する必要があるエンジニアの方もいると思います。 このように、どういうタスクに分解していくかは会社・部署・チーム・個人などである程度決まった型(テンプレート)を作っておくと役に立つと思います。

規模の算出

次にそれぞれのタスクの規模を算出していきます。 ここで重要なのは「主観や判断をなるべく少なくして、機械的に算出する」ということです。 もっとも良いとされているのが、「過去の実績を元に似たタスクから算出する」というものです。 しかしそのためにはこれまでの実績が正しく残っている必要がありますし、「似たタスク」というのがあまり無いケースも多いでしょう。 *1

そこで僕が行っているのは全タスクのなかから平均的な難易度のタスクを選び、それを元に各タスクに難易度を振っていくというものです*2。 難易度は「1, 2, 3, 5, 8, 13, 21」*3ぐらいを用意します。 次に基準となるタスクを一つ決めて、そのタスクの難易度を3(もしくは2)として各タスクに難易度を振っていきます。 難易度が13や21のタスクは現時点ではまだ詳細がわからないや調査が必要というものです。 理想的にはこれらは無いほうがよいのですが、現実的には見積もり時にはわからないことは残っていると思います。

すべてのタスクの難易度が決まったら、基準としたタスクにかかる工数(時間)を算出します。 あとは他のタスクにも時間を掛け算していきます。 たとえば基準のタスクが難易度3で6時間となった場合、難易度に2を掛けた値をそれぞれの工数(時間)とします。

ちなみに、見積もりを他のエンジニアにレビューしてもらう場合は、難易度のままでレビューしてもらうと良いと思います。 工数(時間)でレビューしてもらうと、エンジニアのスキル差によって工数の感覚が違ってくる可能性があるためです。 例えばジュニアなエンジニアが見積もった工数とシニアなエンジニアが見積もった工数では違いが出るのは当然ですよね。 その場合、その二人のエンジニアでタスクの工数について議論をしても有意義なものになりにくいというものです。

スケジュールとは

見積もりの項でも触れましたが、スケジュールとはコミットメントを達成するためにどれだけの期間がかかるかを可視化したものです。 そしてスケジュールを作成するために見積もりを使います。つまり見積もりがあれば、スケジュールを作成するのは簡単です。 むしろスケジュールに関しては作成するよりも、管理するほうが重要でかつ難しいと考えています。

ツール

以降で紹介するスケジュール作成・管理にはMacで使えるOmniPlan*4と呼ばれるガントチャートツールを使います。 OmniPlanを使っているのは、以下の様なスケジュール管理には必須な機能が揃っているからです。

  • リソース: 個々人の稼働率を設定できる
  • カレンダー: プロジェクトの休日、個人の休日、時間外稼働を設定できる
  • ガントチャート: 平準化(自動配置)、基準承認(変更管理)、工数と工期の区別、マイルストーンの設定、遅延タスクの分割

ガントチャートツールには他にもいくつかありますが*5、僕が知る限りのツールはすべて機能不足に感じます。 ちなみにガントチャート以外の方法としてバーンダウンチャートも有名です。 僕はガントチャートのほうが好みですが、スケジュールを正しく作成・管理できるなら好きな方法を採用すればよいと思います。

スケジュール作成

見積もりを元に、タスクと工数を入力していきスケジュール(工期)を作成します。 OmniPlanを使えばタスクと工数を入力して、担当者をアサインしたあとに、平準化(自動配置)という機能を使えばいい感じにガントチャートを作ってくれます。 手動でタスクの配置を設定する必要はありません。

スケジュールを作成する時は以下の点に注します。

  • 非稼動時間を設定する
    • 事前にわかっている非稼動時間はあらかじめ設定しておきます
    • たとえば定例会議、休日、祝日、有給などです
  • 稼働率を設定する
    • 会社に来て対象のプロジェクトに使える割合を設定します
    • 他の人から仕事の相談をされたり、PRレビューをしたり、割り込み作業が発生したりするので個人的には70%〜75%を設定しています
    • 他のプロジェクトを掛け持ちしている場合は40%などになるかもしれません

スケジュールの振れ幅と確率の算出

スケジュールを作成する上でもっとも重要なのが、スケジュールの振れ幅と確率を算出することです。 スケジュールの振れ幅とは最短期間と最長期間との幅のことを表し、確率とはその幅のなかで開発が終了する確率分布を表します。

ありがちなスケジュールは「X月Y日に開発が終了する」というシングルポイントスケジュールです。 これは言い換えると「X月Y日に開発が終了する確率は100%」と言っているのと同じです。そんなことはまずありえません。 なので本来なら「M月N日〜X月Y日の間に開発が終了する確率は75%です」や「Q月R日までに開発が終了する確率は50%です」などのはずです。

そこで開発がほぼ確実(90%〜95%)に終了するであろう期間を最短期間と最長期間として設定します。 私は見積もりを元に作成したスケジュールを最短期間とし、最長期間をそれの1.5倍としています。 確率は50%で開発が終了する日を[最短期間 + (最長期間 - 最短期間) * 0.4]、75%で開発が終了する期間を[50%日 + (最長期間 - 最短期間) * 0.12]としています。 この振れ幅と確率の計算式についてはソフトウェア見積り 人月の暗黙知を解き明かすを参照してください*6

スケジュール管理

スケジュールは一度作成するだけでは全く意味がありません。開発が進むに連れて、スケジュールも更新して、予実管理をしていく必要があります。 私はOmniPlanを使ったスケジュール管理では2つのイテレーションを回しています。

  • 毎日の更新
    • タスクの進捗を記入します
      • 進捗は0%(未着手)、25%(着手)、50%(動くものができた)、75%(レビューに出した)、100%(完了)という粒度で行っています
    • 遅延しているタスクをすべて現在日以降に再配置します
      • OmniPlanの遅延タスクの分割機能を使えば自動で可能です
  • 週1回の更新
    • 残りの期間をもとに振れ幅と確率を計算しなおします
    • 先週(先々週)のスケジュールと比較してどれだけズレが発生しているか確認します
      • 定常的に遅れてきているようであれば見積もりから全体を見直す必要があるかもしれません
      • 突発的に遅れた場合は、稼働を調整したり、タスクの組み換えなどで対応する必要があるかもしれません

このようなイテレーションで予実管理を行い、スケジュールが生きた状態を保ち続けることが大事です。

おわりに

以上、私が行っている開発の見積もりとスケジュール管理の紹介でした。 開発の規模、チームの規模、事業のフェーズ、作るものの種類などによって、この方法をそのまま使えるわけではないと思います。 しかし、これを読んでいただいた方にとって何かしら参考にできるところがあれば幸いです。

*1:例えば受託開発でよく似たシステムを何回も開発している場合は過去の実績から似たタスクを探しやすいかもしれません

*2:プランニングポーカーで使われるポイントと同じ意味

*3:フィボナッチ数列

*4:WindowsユーザにはMS Projectが良いと思います

*5:GanttProject, brabio, GANTTplanner, gantter, Instagantt

*6:この本には振れ幅と確率については見積もりの段階で行うと書いてあります。しかし、チームのメンバーが同じ稼働率、同じスキルレベルの場合はスケジュール作成時に振れ幅と確率を計算するほうが簡単です。