クックパッドの課金を支える技術

f:id:eisuke-oishi:20150409133149j:plain

こんにちは、技術部の大石です。開発基盤グループで課金システムの担当をしています。

インターネットサービスの決済・課金システムの開発や運用は、サービスの根幹を支えるために正確性と機能性を満たさなくてはなりません。また同時に、価格や料金体系、決済手段のバリエーションでユーザーに利便性を提供する必要もあります。「堅牢性」「信頼性」と「柔軟性」「開発スピード」という相反する要素の両立が求められます。

その結果、決済・課金システムは適切な設計や運用を意識しないと複雑になってしまいがちです。

課金システムの開発、運用でよくある問題

複数の決済方法を同じサービスの上で共存させる難しさ

例えば、最初にクレジットカード決済を導入して、その後にコンビニ決済、キャリア決済やアプリ内決済と決済方法が増えていくことはよくあることです。 最初の導入の際にクレジットカード決済への設計だけでなく、その後に増えていく決済を見据えた適切な設計を行なわないと、コンビニ決済やキャリア決済、アプリ内決済をクレジットカード決済の流れに無理矢理押し込めてしまうような実装になってしまいます。

導入当初の段階で複数の決済の流れを把握した上での設計を行なうのは、決済導入の予定があるいくつかの決済のインターフェースや仕様の知識などが必要になったりするため、過去に導入を行なったことがある経験や知見が必要となったりします。 また一度走り始めると根本的な設計を見直すというのは難しくなってしまいます。

割引キャンペーンといった施策の残骸が残ってしまう

ユーザーにサービスの魅力を伝えるために、割引キャンペーンや無料キャンペーンなどの価格面での施策は必ずといっていいほど行ないます。 期間限定であったり、納期の短かいものが多いので、長く運用されるとそのような施策の残骸が残ってしまうことが起きがちです。 そのような残骸がコードの品質を低下させていくことになります。

複数サービス間での運用

クックパッドでも、プレミアムサービスの他にも、プロのレシピ産地直送便などのユーザー課金を行なうサービスがあります。 複数のサービスで決済を導入する場合、課金機能をそれぞれの部署で開発すると外部の決済サービスとの連携などは大半が同じようなコードになったり、運用の知見が部署毎に分散してしまうことが起きてしまいます。

クックパッドの解決方法

以上のような問題を解決するために、クックパッドでは共通決済基盤を開発するというアプローチを取りました。

共通決済基盤とは

クックパッドを起点とする全てのサービスから各種決済の導入ができるようにした、社内向けの独立したWEBサービスです。主な機能としては、

  • 各種決済サービスとの連携
  • 接続先との差異を吸収し統一的なAPI
  • 決済情報、履歴の管理
  • 決済情報の突合や有効性の確認
  • 決済に必要なユーザー情報の管理
  • 経理処理における集計機能
  • カスタマーサポートが履歴を確認したりキャンセルなどを行える管理画面

があります。

なぜWEBサービスとして独立させたのか

たとえば、ロジックをgemとして切り出したり、Rails Engineを使うなど共通のライブラリを使用して管理する方法も考えられます。 しかし、なぜ私達は共通決済基盤をWEBサービスとして独立させたのでしょうか。

それは、WEBサービスとして独立させることにより、共通決済基盤を利用するサービスへの言語、環境的な依存が無くなるというのも理由の1つです。それ以上に大きな理由として、クックパッドのサービスは「プレミアムサービス」を始め、継続課金モデルを採用しているサービスが多いということが大きな動機です。

継続課金は、その名の通り課金状態が継続されていくものなので課金の状態を常に確認する必要があり、都度課金に比べ購入後の管理が複雑になります。 運用の煩雑さを軽減することを考えた場合に、ノウハウが集約されたプラットフォーム上で管理することが必要だったからです。

サービス連携の流れ

それでは、具体的に共通決済基盤が行なっている継続課金の利用開始から、決済情報の突合、サービスとの連携を追ってみることにします。

継続課金の利用開始

f:id:eisuke-oishi:20150409133625p:plain

  1. ユーザーが利用開始のアクションをとる
  2. 決済開始の手続きを決済APIへリクエストする
  3. ユーザーが決済の手続きを行う
  4. 共通決済基盤がサービスへ決済の結果をAPIコールバックする
  5. ユーザーがサービスを利用できる

サービス側での付与が失敗した場合は、適切に共通決済基盤の情報をロールバックします。

決済情報の突合

突合とは、それぞれのサービスが持つ継続決済の一覧同士を比較し差分を検出することです。

f:id:eisuke-oishi:20150409133618p:plain

  1. 共通決済基盤が決済サービスのステータスと同期する
  2. 共通決済基盤からサービスへ差分情報を送信し、サービスは利用できないユーザーの有料機能利用を解除する
  3. 共通決済基盤とサービス側での差分がないかをチェックし、差があれば検知する

上記の処理を、各種決済サービスの情報と共通決済基盤との継続契約の差と共通決済基盤とサービスとの差が無いように毎日行ないます。

以上のような処理が決済手段ごとに存在するするため、各サービスの管理の手間を省くと同時にノウハウが集積された確実な運用を行なうためWEBサービスとして独立させました。

共通決済基盤と利用サービスとの責務の分担

次に共通決済基盤とそれを利用するサービスとの責務の分担について説明します。

課金に関連するストーリーとして、クックパッドでの代表的な例を考えてみます。

  • ユーザーが280円のプレミアムサービス(商品)をクレジットカード決済(決済方法)で、継続課金を契約(注文)し、毎月280円を課金(請求)する。
  • 課金ユーザーがプレミアムサービスの利用ができるようにする(認可)
  • 毎月ユーザーに280円を請求し、結果を検証する

共通決済基盤は「注文」や「請求」の管理や外部APIとの連携を担い、サービス側は「商品」と「決済方法」の選択、サービス利用「認可」を担うように責務を分担しています。

このように、

  • 利用サービス側では商品を割引するクーポンの発行を行なうなど、商品に関する様々な施策が実施
  • 注文や請求の管理、外部の決済サービスとの連携、決済情報の突合などは共通決済基盤のノウハウが集約されたプラットフォーム上で管理

することで、明確な責務の分担を行なっています。

都度課金も対応

WEBサービスとして独立させた理由として継続課金の例を示しましたが、都度課金への対応も行っています。 これにより、サービス開発者は都度課金と継続課金のどちらにも対応でき、ユーザーは継続課金で利用しているものと同じクレジットカード情報を使って都度課金も行なうことができます。

共通決済基盤を導入した結果

各サービスから共通決済基盤を利用することで、冒頭に挙げたよくある問題も解決することができました。

「複数の決済方法を同じサービスとして共存させる難しさ」は1箇所に知見を集約することでよい設計の上で動作させることができています。また、「割引キャンペーンといった施策の残骸が残ってしまう」ことは責務の分担を明確に行なうことで利用サービスでの柔軟性と共通決済基盤の信頼性を担保できています。「複数サービス間での運用」も新規サービスなどでの決済導入コストの削減や運用の負荷軽減に繋がっています。

このように、共通決済基盤を導入することで「堅牢性」「信頼性」と「柔軟性」「開発スピード」の両立ができるようになりました。

まとめ

決済、課金に関する開発や運用は、外部環境の影響が大きく、運用コストが高くなりがちなので頭を悩ますことが多い部分かと思います。クックパッドの例がそういった開発や運用のご参考になれば幸いです。

決済に関する環境は今後テクノロジーの進化や新しい決済方法の登場などによってこれからも進化していく分野です。 そういった外部要因とあわせてクックパッドのサービスの発展に対応していくためにも、共通決済基盤をより良いものに進化させていきたいと思っています。

クックパッドでは、そのような課題に取り組んでみたいというエンジニアを募集しています。

安定したリリースを継続するためのテストとテストレベルの話

こんにちは。技術部の松尾(@Kazu_cocoa)です。

安定したリリースを継続して回す為には、開発プロセスや実装も大事ですが、その中でどのような確認、テストを継続して行うかも大切になります。そこで、開発プロセスにおけるテストをどのように切り分けて、構築していくかという考え方に関して少し整理してみようと思います。

これにより、実施されているテストによって検出できる/できない不具合がどのようなものか、それが開発中のどこで防ぐことができるのかを整理できるようになってくると思います。また、安定したリリースを実現するためのボトルネック解消に向けて、どのレベルでテストを充実させると効率的にそれが達成できるかという所も考えることができるようになります。

テストレベルによるテストの区分け

テストレベルという言葉にも様々な定義がありますが、ここではざっくりとテスト対象となる範囲や領域を意味することにします。その中で、ここではUnit Test、Integration Test、Feature Test、という用語を使います。主にテスト対象となる範囲が順に広がることを想像してください。それらがどのようなことを確認するのかは後述していきます。

このようなテストレベルを考えると、開発物をリリースするまでに、どこで、どんなテストを構築して、安定したリリースにもっていくかという流れとその実際を考え易くなります。(多くのテストエンジニアの方々は単なる共通の理解を促進する為の枠組みなだけであることも知っているでしょう。)

以下ではそのテストレベルに関して、Androidアプリ開発において自動化されるテストを例に書いていきます。

  • テスト対象
    • プッシュ通知を受け取るAndroidアプリ
  • シナリオ

    • GCMにより端末がプッシュ通知を受け取ってから、intentによりActivityを起動する(アプリの外側の話(OSやネッワークの状態など)は除外)
      • 前提: GCMによるプッシュ通知がテスト対象の端末に到達する
        1. システムによりBroadcastされたプッシュ通知をアプリが受け取りintentを生成する
        2. 生成したintentをActivityにセットする
        3. ユーザが起動されたActivityを利用する
  • 補足

    • Androidはintentの受け渡しによってそれぞれのActivityを連携させます(Activityが画面を構築する一要素)
    • 開発中にこのintentが壊れたり、Activityを表示するときに参照される要素のいずれかが壊れると容易にアプリがクラッシュするという状態になります

この例に対して、Unit Test、Integration Test、Feature Testといったテストレベル毎に、よく実施される形のテストコードを例として書きます。それにあわせて、それぞれのテストレベルではどのようなことに注意しながら確認やテストを行うのかと補足していきます。

Unit Test

テスト対象のオブジェクトが正しく振る舞っているか?を確認するテストです。AndroidだとよくActivityUnitTestCaseやAndroidJUnit4を使って、特定の関数の動作を確認します。

例えば、以下のようなintentを生成するクラスがあった場合、その中の関数を対象にテストコードを書きます。

テスト対象例

public class ExampleIntent {
    public static Intent createIntent(Context context) {
        Intent intent = new Intent(context, MainActivity.class);
        intent.setAction(Intent.ACTION_VIEW);
        intent.putExtra("example", "extra data")
        return intent;
    }
}

テストコード例

@RunWith(AndroidJUnit4.class)
public class ExampleIntentTest {
    @Test
    public void createIntentTest() {
        Intent intent = new ExampleIntent.createIntent(InstrumentationRegistry.getTargetContext());
        assertThat(intent, is(notNullValue()));
        assertThat(intent.getStringExtra("example"), is("extra data"));
    }
}

この段階では、非常に限定された範囲における確認を高速に実施できます。オブジェクトに対して使われる値の組み合せや異常な値が代入される時のテストコードも書いておけば、限定された領域において常に動作を確認できます。

Integration Test

複数の関係性を持つオブジェクトやActivityを絡めたテストを実施します。複数の関係したオブジェクトを跨いだ処理が、期待する動作をするかを確認します。

ここでは、実際にintentを受け取ったとして、そこから期待するActivityが正しく起動することを確認します。Unit Testよりもテスト実行に時間がかかります。ただ、後述するFeature Testと比べると十分に高速です。

テストコード例

以下では、先ほどのintentを使いMainActivityを起動する、ところを確認するテストコードになります。

@RunWith(AndroidJUnit4.class)
public class LaunchActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
    private Instrumentation instrumentation;
    private Instrumentation.ActivityMonitor activityMonitor;
    private Context context;

    public LaunchActivityTest() {
        super(MainActivity.class);
    }

    @Before
    @Override
    public void setUp() throws Exception {
        instrumentation = InstrumentationRegistry.getInstrumentation();
        injectInstrumentation(instrumentation);

        super.setUp();  // injectInstrumentationを先に実施しないとsuper.setUp()が失敗するため
        context = InstrumentationRegistry.getTargetContext();
        activityMonitor = instrumentation.addMonitor(MainActivity.class.getName(), null, false);
    }

    @Test
    public void launchActivityByExampleIntent() {
        launchActivityWithIntent(
                context.getPackageName(), 
                MainActivity.class, 
                new ExampleIntent.createIntent(context));

        activityMonitor.waitForActivityWithTimeout(2000);
        assertThat(activityMonitor.getHits(), is(1));
    }
    
    @After
    @Override
    public void tearDown() throws Exception {
        instrumentation.removeMonitor(activityMonitor);
        super.tearDown();
    }
}

上記では要素の表示までは気にしていません。表示も確認したい場合、例えばEspressoを使い、起動したActivityに期待する要素が表示されているとをassertとして確認も可能です。

この辺のレベルでは複数要素が絡むため、依存関係が発生することが多いです。その場合、Dependency Injectionを使うなりして、依存関係が発生する箇所をうまいこと分離して、独立した形でテストを実施する動きが活発です。

Unit Test、Integration Testの段階で、表示要素に対する操作を除く要素の組み合せをテストできていることが多いと思います。

Feature Test

特定の機能に注目し、それが目的を達成できるか確認します。ユーザがxxxを達成できること、というような粒度を意図しています。そのため、ここのレベルでのテスト自動化を行おうとするとEspressoやAppiumを使うことが多くなると思います。人手による確認やテストも増える領域です。

例えば、プッシュ通知を受け取ったアプリが正しくActivityを起動したとして、そのActivityに対して何らかのユーザ操作が実施される、ということを確認します。AndroidではEspressoで提供される関数を使ってみると以下のようなことができます。プッシュ通知の模倣は、実際にサーバから送るでも良いし、adbによるBroadcastの送信でも良いと思います。

@Test
public void usersCanClickItems() {
    onView(withId(R.id.example)).check(matches(withText(R.string.example)));
    onView(withId(R.id.example)).perform(click());
}

このレベルでは人手で実施する必要があったり、自動化されたテストを行うにしてもIntegration Testなどに比べると十分に遅いです。そのため、このレベルで表示条件の網羅などを行うと必要以上に無駄を作ってしまいます。さらには、十分に確認を網羅できずに不具合を作り込んだままリリースしてしまうかもしれません。そのため、Unit TestやIntegration Testで実施可能なテストをできるだけ増やす方が望ましいです。(一般的にその方が良いとも言われますね。)

なお、このテストレベルのテストに多くを頼っている場合、リリース毎に大きな心労と労力を払うことになりますね。

ただ、このレベルにならないと確認できないことがあります。例えばシングルサインオン(以下、SSO)を行うような複数アプリの連携が必要になる類いのテストです。

弊社ではクックパッドアプリの他にも、撮るレシピといったアプリをリリースしています。これは、"写真を撮る"ことでレシピなどの情報を保存、必要なときに見るというアプリです。このアプリは、クックパッドアプリ本体アプリがインストールされているとSSOで簡単にログインすることができます。この場合、複数のパッケージを跨いだ形でテストを行う必要があります。Appiumやuiautomatorの機構を使うと以下の流れでテストを自動化可能です。

  1. クックパッド本体をインストール・ログインする
  2. 撮るレシピをインストール・(SSOで)ログインする

これにより、"SSOにより撮るレシピでログインできる"という機能を確認することができます。

この他、端末システムに依存するような類いのテストも、この粒度では自動化されたテストの一環として実施できます。例えば以下です。

  • シナリオの特定のタイミングでフライトモードに設定を変更して意図的に通信を遮断するようなテストケース
  • 特定の時間に設定を変更してアプリを操作するようなテストケース

テストレベルによる区分の締めとクックパッドにおける実情

Androidアプリを例に、大きくUnit Test、Integration Test、Feature Test、という3種類にテスト対象の領域を区分し、テスト対象とする範囲とどのようなことを確認するか、という流れを記述しました。

テストレベルの定義自体、属する組織や開発スタイルに依存するものなので一概にこれが正しいとは言い切れません。一方で、ある程度テスト対象の領域をこういう言葉で区分しておけば、どのレベルでどんな確認を担保するという話、安定したリリースサイクルをまわすにはここの機能で不具合発生が多いことがボトルネックだから、どのレベルでどういうふうに対応しよう、といった話ができるようになります。

各テストレベルに対する説明を書きましたが、弊社Androidアプリにおいても十分なテストはまだ整備されてません。ここでいう十分とは、コードの変更に対して正しくテストが失敗してmasterへマージする前に開発者が気づけるとか、変更に伴う不具合を検出しきれずにリリースすることを防ぐ、という粒度の話をさします。現在はテストを実施する速度に対するボトルネックとなるFeature Testのレベルからある程度テストを自動化してカバーしつつも、Integration / Unit Testへと手を入れ始めています。今後、さらにIntegration/Unit Testを増やしたり、テストし易いコードに修正していき、より安定したリリースの実現を目指しています。そして、より人は人に近いところのテストに力を注ぐことができる環境を作りたいですね。

その他のテスト

少しテストレベルとは脱線するのですが、最近よく耳にするxxxTestと呼ばれるテストをあげておきます。テストレベルでは単純にテスト対象とする範囲に注目していましたが、他にも周辺環境や確認したい箇所に集中して呼び名がある、という例です。

Hermetic Test

今回はテスト対象の周辺環境には言及していません。テスト対象の環境まで言及してみると、モックやフェイクサーバを用意した上で、閉じられた環境で実施するテストをHermetic Testと呼びます。

時折私はWireMockにJsonを与えたスタンドアローンのサーバと、iOS/Androidアプリを起動し、限定された範囲内でクライアントに着目したテストします。これも単純なHermetic Testの環境ですね。

GUI Test

最近よく耳にする各種ボタン操作に対する動作を確認したり、スクリーンショットでレイアウト崩れを確認する、ということに焦点を当てるテストはGUI Testとよく呼ばれます。(ソフトウェア品質知識体系ガイド -SQuBOK Guide-(第2版)より)

GUI越しに操作可能なテストを行うときは、自然とこの観点のテストを行う人が多いと思います。Androidでは、 screenrecord コマンドを使うことで、スクリーンショットだけれなく動画の撮影も用意に行えるので、iOSに比べて特別なツールなく確認できる範囲が広いのではないでしょうか。

まとめ

今回は、テスト対象の範囲を変化させながら、テストレベルという切り分けで実施されるテストの話を書きました。また、これらを使うことで、不具合作り込みのボトルネック解消であったり、よりプロジェクトに必要なテストの領域を考える手助けとなることを書きました。

テストエンジニアの方々からするとおそらく息をするような範囲の話ですが、多くの人も意識している/していないにせよ想像に沿ったものだったと思います。いずれにせよ、ここは定義問題であるだけ、という見方もできますが、その定義をある程度持っているだけで目的とその実施内容に対する考えを行い易くなります。

モバイルアプリの開発は、多くがサービス主体の開発に移ってきたように思えます。そのような中で、長く改善を続けていくにはどこかのタイミングで少しずつ整備された開発/テスト環境を整えることが大事です。そのとき、必要なテスト設計を行い、それを実施・評価するサイクルを回すことができるということは、質の高い製品の開発体制を築く礎になってきます。そんな時に今回の話が少しでも寄与できると嬉しいですね。

弊社ではこのような取り組みを共に実施し、より良いサービスを提供し続ける為にエンジニアを募集しています。ご興味のある方は、是非とも覗いてみてください。

新規サービスの管理画面を短期間で見栄え良く実装する

こんにちは、クックパッド料理教室の京和です。

管理画面はほとんどのウェブサービスに存在し、ユーザサポートやサービスの状況・KPIなどを確認するために、スタッフが毎日利用するとても重要なものです。にも関わらず、新規サービスでは人員が不足していることから、ついおざなりなデザインや実装になりがちなのではないでしょうか。

今回はクックパッド料理教室で採用している、RailsのMountable EngineとBootstrapのデザインテンプレートを使った、見栄えがよくメンテナンスしやすい管理画面を短期間で実装する方法についてご紹介します。

Mountable Engineとは

Mountable EngineはRailsアプリケーション上で動く、ミニRailsアプリケーションのようなものです。 ミニと書きましたが、Railsアプリケーション(Rails::Application)はRails::Engineクラスを継承しており、Mountable Engineの実態はまさにこのRails::Engineクラスです。
こうした事ができるのはRailsのマイクロカーネルアーキテクチャのおかげです。

Railsの内部構造やその思想・哲学については少々古い資料にはなりますが、@amatsuda が執筆したWeb+DB PRESS Vol.58の特集「詳解Rails 3」で詳しく解説されており、非常にオススメです。

簡単な使い方紹介

Mountable Engineは以下のコマンドで簡単に作ることができます。

rails plugin new asterisk --mountable

実行すると #{Rails.root}/asterisk 以下にファイルが生成されます。 下記のとおり、Railsアプリケーションとよく似た構成になっていますね。

asterisk
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.rdoc
├── Rakefile
├── app
│   ├── assets
│   ├── controllers
│   ├── helpers
│   ├── mailers
│   ├── models
│   └── views
├── bin
├── asterisk.gemspec
├── config
├── db
├── lib
└── spec

ControllerやViewはもちろん、Gemfileやroutes.rbなども用意されています。bin/railsコマンドもあるので、scaffoldなどのGeneratorを利用することも可能です。
こうして生成したMountable Engineは、本体のGemfileとRoutingに定義することでアプリケーションから呼び出す事が可能です。

Gemfile

gem "asterisk", path: "asterisk"

config/routes.rb

mount Asterisk::Engine => '/', constraints { subdomain: 'asterisk' }

ここではconstraintsのsubdomainオプションを使ってドメインを分けています。
Mountable Engineは通常のRailsアプリケーションとほとんど同じ感覚で書くことができます。Engineについての詳しい解説はRailsGuidesをご覧ください。

なにが嬉しいのか

Mountable Engineを使った際の利点は、端的に言うとアプリケーションを分ける場合と分けない場合の「いいとこ取り」ができることです。

管理画面を別アプリケーションとして実装する場合、コードの共通化、特にモデルのメソッドやValidation・Scopeなどの共通部分をどのように管理するかが課題となることが多いです。多くの場合シンボリックリンクやgit submodulesを使うと思いますが、実運用は厳しいのが実情だと思います。一方で、管理画面を同じアプリケーション内に実装した場合、ユーザ用アプリケーションと密結合することになり、セキュリティやメンテナンスコストについて不安を抱えます。

Mountable Engineの場合、名前空間とコードベースを分離しつつ、モデルのコードは共通して呼び出すことができますし、更には管理画面でしか使わないテーブルであれば、Engine側にのみモデルを定義すると言ったことも可能です。別のアプリケーションとして切り出したいといった場合も比較的容易にできるでしょう。

料理教室ではスタッフ向けの管理画面と先生向けの管理画面を別々のMountable Engineとして実装していますが、1つのアプリケーション内にこれらが混在していた場合、メンテナンスするのはかなり難しかったと思います。

Bootstrap Templateを組み込む

Bootstrapのデザインテンプレートは有償・無料含めて様々なものがあります。少しググれば沢山のものが見つかるでしょう。 クックパッドではAce - Responsive Admin Template(有償)やAdminLTE Template(無料)などが使われています。
数年前は有償の方がクオリティが高かった印象がありますが、最近は無償でもハイクオリティなものが増えてきているように感じます。

導入はほとんどの場合、ファイルをapp/assets以下などのAsset Pipelineのパス以下に置くだけでOKです。Mountable Engineの場合はアセットファイルも分離されるので、本体とは異なるデザインテンプレートも気軽に設置することができます。

欠点

Mountable Engineは名前空間が分かれてるとは言え1つのRubyプロセスで動いているため、相互で参照することが可能です。 モデルを共通化できることは便利ですが、一方でコンテキストが異なるアプリケーションが混在している状況でもあるため、さじ加減を間違えると技術的負債になってしまいます。例えば(どんなアプリケーションにも言えることですが)default_scopeは原則使わないほうがよいでしょうし、Concernに分けて実装すると言ったことも必要です。

また、子(Engine)から親(Application)への参照以外にも、やろうと思えば親から子のモデルを参照することもできてしまいます。当初は管理画面でしか使わなかったためMountable Engine内に実装したモデルが、仕様変更が続いた結果ユーザ向けアプリケーションからもよく参照されるようになっていた、と言った事例がありました。

サービスは日々変化していきますから、コードベースもそれに合わせて適宜リファクタリングをしていくべきでしょう。とはいえ、こうした問題は、通常発生する技術的負債とあまり変わらないと思います。

Appendix:

その他、管理画面で気をつけている事などを書いてきます。

管理画面に名前をつける

料理教室では私たちの管理画面を「Daddy」と呼んでいます。名前の由来はクックパッドの歴史に触れるので詳しくはお話できないのですが、他のサービスの管理画面でも同じように名前を付けている事が多いです。
名前を付けることで、ともすれば無機質な印象のする「管理画面」から、毎日扱う「サービス」となり、より愛情を注ぐことができます。愛着をもてる名前を考えることはとても重要だと思います。

ガイドラインをつくる

クックパッドではドメインの分離や認証方式・監査ログの取得など、管理用アプリケーションを実装する際のガイドラインが定められています。原則として、すべてのサービスの管理画面でこのガイドラインを満たすことが求められており、これらがセキュリティやコンプライアンスを担保しています。そして、それらの実装を支援するため、共通ログ基盤Figlogなどの様々なライブラリが存在しています。

おわりに

Mountable EngineとBootstrap Templateによる管理画面の実装は、私が料理教室事業部に配属された当初、管理画面がとても貧弱だったことからついカッとなってリニューアルしようと考えたことがきっかけでした。調査やBootstrap Templateの選定なども含めて3日程度で実装は完了し、メンバーからはとても喜ばれました。また、幾つかの新規サービスでも同様の構成が採用されることになり、サービス間での管理画面の実装方式が共通化されると言ったメリットも生まれました。
配属直後で高まっている意識と比較的余裕のある状況は、チャレンジのしやすい大きなチャンスと言えるかもしれません。

管理画面は毎朝必ず見るもので、利用する時間は業務の中でも大きな割合を占めます。管理画面を素敵にして毎日の業務を楽しくすることは、毎日の料理を楽しみにし続けていくためにとても重要なことだと考えています。

クックパッド料理教室ではエンジニアを募集しています。 サービスに興味をお持ちの方はぜひこちらからご連絡ください。