Upgrade to Pro — share decks privately, control downloads, hide ads and more …

動き出したクックパッドのCtoCビジネス

1amageek
February 14, 2018

 動き出したクックパッドのCtoCビジネス

2017の春からクックパッドはCtoCビジネスを開始することを公言していました。本日は新規サービスを発表させて頂きます。

その名も「Komerco」(コメルコ)です。

Komercoはモノで毎日の料理を楽しくするプラットフォームです。Cookpadは毎日の料理を楽しみにすると言うミッションを掲げています。
Komercoはその中でも、モノで毎日の料理を楽しくすると言うポジションでサービスを展開します。

もので毎日の料理を楽しくするとはどう言うことでしょうか?
これはKomercoのプロダクトオーナーのInstagramです。

料理を美味しく作れる鍋、
美しく飾ることができる器
料理は楽しくなると考えました。

世界にはたくさんの素晴らしい作品にあふれています。
日本には素晴らしい作品を生み出すクリエーターがたくさんがいます。Komerco は素晴らしいモノを提供するクリエーターと
料理をする人を結びつけるサービスです。
Komercoではすでに素晴らしい作品を生みだす100人のクリエーターを獲得しています。

Komercoについてもう少しお話します。Komercoは三つの要素から構成されています。
EC・Media・cookpadの三つです。

Komercoはこの春リリースです。

さてKomercoの開発の裏側に話を進めていきましょう。
みなさん昨日のクックパッド のDevelopers Blogみていただけましたか?
今日はそのあたりの話をもう少ししようと思っています。

まずKomercoチームの紹介をします。
特に注目して頂きたいのがエンジニアに関してです。Komercoにはサーバーサイドエンジニアがいません。

Komercoはサーバーレスで開発されています。KomercoのバックエンドはFirebaseです。

なぜFirebaseなんでしょうか?

私がWEB興味をもち、最初にサービスを作り始めたのは2009年でした。Railsが普及し始めNode.jsが生まれた年です。当時は私は夢見がちな要件定義をたくさんしていました。
もちろん失敗しました。開発を行った事がない素人には夢見がちな要件は重すぎたからです。

次はチームを組んで開発を行うことにしました。
この頃はMEANという開発方法が登場し、Node.jsが普及し始めた頃です。

これも失敗しました。開発者の技術力の差によって、サーバーサイドとクライアントサイドの進捗に大きなズレが起こりました。その結果チームのモチベーションを維持できなくなっていました。

前の反省を生かしてmBaaSを導入することにしました。
Facebookが提供していたParseと言うサービスを利用していました。このときは、開発も順調に進みました。サーバーサイドのことを考える必要がなくなったため、開発が非常にシンプルになりました。この頃から私はREST APIを使うことがなくなりました。

しかし失敗しました。Facebookが突然、Parseをクローズさせたんです。そして2016年 Googleに買収されたFirebaseがとてつもなく素晴らしいものになってリリースされました。
このタイミングで私はFirebaseに飛びつきました。

そこからFirebaseの研究を進め、Komercoの開発に至りました。
Firebaseに到るまでに長い歴史があるんですねぇ。
そしてParseのようになるまいとGoolgeさんと仲良くさせてもらいながらコミュニティを盛り上げて行っています。

開発がうまくいかなかったのはなぜでしょうか?
エンジニアスキルですか?
納期ですか?
チームの結束ですか?

私が思うに全ては開発が遅いことだと言う思います。
開発が遅くなる原因はたくさんありました。しかし、逆説的にとにかく開発が早くなればあらゆることが解決されると考えました。

想像してみてください。
鉛筆で書いて消しゴムで消すように仕様変更ができて、想い描いたことを直ぐに形にできる開発ができればどうですか?
きっと未来は明るいんです。
私は現在存在するバックエンドのサービスの中でFirebaseがそれをもっとも近い存在だと考えています。

Firebaseの特徴を3つご紹介します。
・高速に開発できること
・簡単にセキュリテイを担保できること
・フルマネージドです。

FirebaseはクライアントからDBへ直接Writeを行います。
APIを通す必要がないのでAPIを開発する必要すらありません。
どのくらい簡単かお見せしましょう。

SwiftでUserを定義して保存、取得、更新を行なっています。
非常に簡単ですよね?
もう一つ例をお見せします。サービスを設計する上でDBを正規化することって辛くないですか?少なくとも私はRDBの設計をするのは結構辛いです。

Firebaseではこんな分にリレーションを表現できます。
ここではUserとGroupの二つを定義しました。

UserがGroupsをもちGroupがUsersをもち
お互いに参照を持つ事ができるようになっています。

ここでは三つのインスタンスの関係性を表しています。
相互参照して、最後に保存します。これだけです。非常にシンプルですね。

次にセキュリティについて紹介します。
Firebaseのセキュリティはルールファイルを定義する事で行います。

これがルールファイルです。
このルールでは、UserがReadできるのはAuthを持っていることクライアントである事、またWriteできるのは自分だけと言うことを表しています。

最後にインフラについてですが、Firebaseはオートスケールします。インフラの監視に悩まされることはありません。
Firebaseを例えるなら、開発における鉛筆と消しゴムと無限のキャンバスです。速そうな気がしませんか?

でもまだまだ加速できる
車輪の再発明を可能な限り少なくしていきましょう。

私たちはオープンソースを利用しています。みなさんもサービスを作るときはお世話になっているんじゃないでしょうか?
もちろんKomercoでもOpenSourceを利用しています。

そして私たちは、利用するだけじゃありません。作り出して公開しています。

なぜOpenSourceを提供するんでしょうか?
それは、少人数で品質を担保するためです。

OpenSourceにすることで品質が向上します。
エンジニアは、外部に出すことを考え始めた瞬間に依存性を考えるようになり、自ずと疎結合な設計がされていきます。
自分のチームでしか使わない頭になった瞬間コードはへの妥協は必ず増えていきます。心理的なことですが、非常に効果があります。

この後、私がちが作ったOpenSourceを紹介しますが、そのOpenSourceはすでに、海外のスタートアップでも利用されています。
バグ報告もたくさんもらいます。
OpenSourceにすることでチーム以外の人が自分たちの開発を手伝ってくれるんです。

そして、再利用ができる。
これこそGive and Takeです。私たちが作ったOpenSourceは社内の他のチームでも利用されています。
こうすることで他のチームはさらに高速な開発ができるようになります。

Komercoの技術を公開しています。のぞいてみてください。

今日は特に次の二つをご紹介します。
PringとOrderableです。

高速に開発できそうじゃないですか?

高速化した先に何があるんでしょうか?
ただ早く作ることになんの意味があるのか?

開発が高速化されることで
大胆な戦略を取る事ができるんです。

複数回の仕様変更ドンとこい。Komercoでも要件の漏れや、仕様の拡張を何回行いました。高速化していない状態で、4人でECを立ち上げようとしていたら複数回の仕様変更はかなりの痛手だと思います。

消耗しないは言い過ぎですが、想い描いたことを直ぐに実現できる環境は非常に精神的なストレスを軽減します。

要件が多くあっても仕様で衝突したり悩む事が劇的に少なくなります。

最後にこれは非常に重要です。
たくさん試す事ができるようになります。
サービスの設計をするとき、感覚的意見な衝突で悩むことはありませんか?このUIの方が、こっちのUIの方が、あれの方が
あると思います。

しかし残念ながら、いくら議論しても時間の無駄です。
結論は市場しか知らないんです市場に聞きましょう。

たくさん試しましょう。想い描いたことをとにかく試して事実を確立していきましょう。
そうする事で、少しづつですがサービスは確実に成長していきます。

最後にまとめさせていただきます。

Komercoは今年の春にリリースします!

KomercoはFirebaseで開発されています。

Komercoで使われいるテクノロジーを公開しています。

クックパッドを新しいサービスを高速で開発して行きます。

最後に動きだしたクックパッドのビジネスにご注目ください。

1amageek

February 14, 2018
Tweet

More Decks by 1amageek

Other Decks in Technology

Transcript

  1. EC

  2. iOS Engineer Product owner Director 1 1 4 4 Designer

    1 Our team Customer support 2 Creator scout
  3. iOS Engineer Product owner Creator scout Director 1 1 4

    4 Designer 1 Our team Customer support 2 αʔόʔαΠυͷΤϯδχΞ͕͍·ͤΜ
  4. 2009 Node.js MEAN 2013 2015 Parse Rails 2016 Firebase ເΈ͕ͪͳཁ݅ఆٛ

    νʔϜϏϧσΟϯά։࢝ Firebaseಋೖ mBaaSΛಋೖ REST APIͱܾผ
  5. 2009 Node.js MEAN 2013 2015 Parse Rails 2016 Firebase ເΈ͕ͪͳཁ݅ఆٛ

    νʔϜϏϧσΟϯά։࢝ 2018 Komerco mBaaSΛಋೖ REST APIͱܾผ Firebaseಋೖ
  6. // SAVE let user: User = User() user.name = "1amageek"

    user.save() // GET User.get("user_id") { user, error in if let error = error { print(error) return } print(user) // UPDATE user?.name = "Norikazu Muramoto" user?.update() } @objcMembers class User: Object { dynamic var name: String? }
  7. @objcMembers class User: Object, UserProtocol { dynamic var name: String?

    let groups: ReferenceCollection<Group> = [] } @objcMembers class Group: Object, UserProtocol { dynamic var name: String? let users: ReferenceCollection<User> = [] }
  8. @objcMembers class User: Object, UserProtocol { dynamic var name: String?

    let groups: ReferenceCollection<Group> = [] } @objcMembers class Group: Object, UserProtocol { dynamic var name: String? let users: ReferenceCollection<User> = [] }
  9. let user0: User = User() let user1: User = User()

    let group: Group = Group() // ૬ޓࢀর͢Δ user0.groups.insert(group) user1.groups.insert(group) group.users.insert(user0) group.users.insert(user1) // อଘ͢Δ group.save()
  10. service cloud.firestore { match /databases/{database}/documents { // user match /user/{userID}

    { allow read: if request.auth != null; allow write: if request.auth.uid == userID; } } }
  11. service cloud.firestore { match /databases/{database}/documents { // user match /user/{userID}

    { allow read: if request.auth != null; allow write: if request.auth.uid == userID; } } }
  12. // Shop let shop = Shop() shop.name = "͏ͭΘγϣοϓ" //

    Product let product = Product() product.name = "࣫ృΓͷث" product.hashtags = ["ث", "࣫ృΓͷث"] // SKU let sku = SKU() sku.stock = 10 sku.price = 2000 sku.shop.set(shop) sku.product.set(product) shop.products.insert(product) product.shop.set(shop) product.skus.insert(sku) shop.save()