TECH PLAY

BASE株式会社

BASE株式会社 の技術ブログ

574

サーバサイドエンジニアの宮村です。 カートの負荷試験について、第3弾の記事です。 最初の記事 でも触れましたが、今回の負荷試験実施にあたり、外部サービスを模擬するモックサービスを作成しました。 外部サービスへ接続する負荷試験を行うには 今回、負荷試験の対象としたのは、BASEのカートシステムです。 カートシステムには決済時に外部サービスを利用する箇所があり、通常の開発時には、外部サービスより提供されている検証環境へ接続しています。 一般的に提供されている検証環境は、本番環境ほどの性能ではなかったり、他の利用者と共用しているというものではないでしょうか。そのため、利用者の都合で自由に高負荷をかけることは難しいと言えます。 負荷試験のような高負荷をかけることが可能か否か、また可能な場合、自由に実施してよいか、事前申請が必要かなどを確認し、それなりの準備を行う必要があります。 また利用が可能だったとして、外部サービス要因でパフォーマンス影響が出る懸念、送信するリクエストの制約など、外部サービスの提供する環境を使用する場合に考慮しなければならない点がいくつかあることがわかってきました。 外部サービスへ接続しない 一方で、提供されている検証環境を使用せずに負荷試験を実施することについて検討します。 提供されている検証環境と同等の動作をするモックサービスを用意し、接続先を変更する 提供されている検証環境へ接続する処理を、外部接続せずに処理が完了するように変更する いっそのことすべてを本番環境で行う 本番環境との差異を小さくするという点において、3を除けば、プログラムの変更が少なくなる1の方法が有利と言えそうです。 稼働中のサービスで3を行うのは、リスクが高い上に、検証等の準備を含めるとコストが低いとは言えません。 調査を行ったところ、用意するモックサービスは、 BASEのサービスからのリクエストに対して 処理可能な形式のレスポンスを 適切な時間をかけて返してくれれば十分 という見通しを持つことができました。 これであればモックサービスを準備することが有力な選択肢になるだろうということになり、検討を始めました。 モックサービスとしてSwaggerを検討する さて、モックサービスをどのように準備するかということになり、調査を開始しました。 たとえば Swagger は、決まったレスポンスを返すモックサーバとして動作してくれるようです。作成したAPI定義がドキュメントとして残るなら、それも良さそうに思えます。 ただし、「適切な時間をかけて返す」という部分が解決できないようで、採用を見送ることにしました。 ここでふと、 sleep(1); したいだけであれば、PHPで書いてしまえばよいのでは?と思い直し、PHPで作ってみることにしました。 PHPなら普段から書いていますので、キャッチアップのコストは不要です。 FastRouteで行為に高速なモックサービスを実装する 簡単なPHPで書けるだろうと高を括っていたため、特にウェブアプリケーションフレームワークは使用せずに実装をはじめました。 今回用意したいモックサービスのエンドポイントが8つほどあります。 いくつか似たものはあるものの、バリエーションのあるURIであったため、ルーティングがあるといいなと思いました。 そこで FastRoute を使うことにしました。これでルールの一定しないエンドポイントでも、仮にエンドポイントを増やす場合にも拡張が容易になります。ずいぶん楽になりました。 <? $ dispatcher = FastRoute\simpleDispatcher ( function ( FastRoute\RouteCollector $ r ) { $ r -> addRoute ( 'GET' , '/users' , 'get_all_users_handler' ) ; // {id} must be a number (\d+) $ r -> addRoute ( 'GET' , '/user/{id:\d+}' , 'get_user_handler' ) ; // The /{title} suffix is optional $ r -> addRoute ( 'GET' , '/articles/{id:\d+}[/{title}]' , 'get_article_handler' ) ; }) ; こんな感じで簡単に書けました。(サンプルより引用) あとは、事前に調査しておいた資料をもとに、エンドポイントごとのレスポンスと応答時間を設定していきました。これは地道な作業です。 一通り書き上がったところで開発環境の接続先を変更し、疎通確認を行います。HTTPリクエストヘッダを使用している箇所などのいくつかの修正を行い、ついに注文が完了できるようになりました。 これで、設置してcomposer installするだけで使えるモックサービスの完成です。 実戦投入 負荷試験実施の際には、AWSのEC2に設置し、期待通りのレスポンスを返しているかを確認しながら使いました。 試験中、何度か期待通りのレスポンスが出ないことが検知されることがありましたが、Apacheの設定値の調整などを行うことで期待通りの役割を果たしてくれました。 これはモックサーバの設定を見直していたときのやり取りでした。 モックサービスなので、実在するクレジットカード番号を使う必要もなければ、メールアドレスの重複を気にする必要もありません。 シンプルなテストシナリオを繰り返し実行することができ、便利に使用することができました。 まとめ 提供されている検証環境を使わずに自前でモックサービスを作成、使用することも、負荷試験時の選択肢としてアリだと思いました。 モックサービスを自由にできることで、アプリケーションやテストシナリオをシンプルにできる点も良いと感じました。 今後、他の外部サービス連携にかかわる部分の負荷試験を行う際も、同じ要領でモックサービスを活用することができそうです。 最後に これまで3回にわたり、負荷試験関連のトピックを紹介させていただきました。興味がある方は、過去の記事も参照いただけると嬉しいです。 devblog.thebase.in devblog.thebase.in パフォーマンスに関する改善に終わりはなく、また別の課題に向けて取り組んでいる最中です。 BASEでは、カートのパフォーマンスアップに興味がある方をお待ちしております! open.talentio.com
アバター
フロントエンドエンジニアの松原( @simezi9 )です。BASEでは現在 ショップ向けの管理画面をリニューアルするプロジェクトが進んでいて 、UI/UXの更新と同時に創業当時から継ぎ足して作ってきたフロントエンドの技術スタックを一新しようとしています。この記事では、具体的にそのフロントエンドの更新でどのようなことに取り組んでいるのかをいくつかご紹介したいと思います。 Vue + TypeScriptを利用したMPA(multi page application)化 HTMLの構築をPHP(サーバーサイド)からJS(クライアントサイド)へ移行する 従来の「BASE」の画面ではPHPでHTMLの構築を行っていましたが、HTMLの構築をすべてPHPのコードから分離させて、Vueによるクライアントサイドでのレンダリングにしています。また管理画面の特性上(1ページあたりの閲覧時間が長く相対的にローディングの時間が短くなる)、サーバーサイドレンダリングなどは特に行っていません。 クライアントサイドでのRoutingの導入 Routingに関しては管理画面の機能を大きな単位でいくつかに分割して機能間のRoutingはCakePHPで行い、機能内ではSPAのようにクライアントサイドで細かくRoutingを行っていく構成になっています。フロントエンドのRoutingはVue Routerを利用しています。 大雑把に責務を整理すると以下のようになります。 PHPサーバの役割 大きな機能単位でのRouting RestAPIの提供 Javascript(Vue.js)の役割 機能内でのRouting 画面の描画 RestAPIの構築とAPI Blueprintによるカタログの作成 データの取得・操作は基本的に全てAPI経由で行えるように必要なだけのAPIを用意しています。作成したAPIはAPI Blueprintを利用してカタログ化されていてサーバサイドのエンジニアとフロントエンドのエンジニアが疎結合に作業を進めていけるようになっています。 フロント側でも基本的にAPIの構成と1エンドポイントに対して1ファイルで対応するようにinfra層を構築しています なぜVue+TSか もともとBASEではHTML/CSS/JSによるフロントの構築をすべてデザイナーが担っていてフロントエンドエンジニアというポジションはありませんでした。この次世代管理画面プロジェクトでのフレームワーク選定もデザイナー陣主導で行われました。そのなかでRiot.jsやReactなども試した上で、Vue.jsがもっとも技術導入がスムーズに出来そうだという結論となりVueを採用しました。 また、プロジェクトのサブテーマとして「次の5年を支える」というものがあり、TSが提供する型システムによる安定性がプロダクトのライフサイクルをサポートしてくれることを期待してTSを導入しています。 開発していて実際どうか? 現行のVue2.xとTSの組み合わせはReactなどと比べると劣る面があることは否めない(props周りなど、型が失われてしまう場所が多い)ですが、API通信などのVueが絡まない部分でのTSの型システムのサポートは非常に強力ですし、Vueの次期メジャーバージョンであるVue3.0では コアがTSに移行し、サポートの強化も表明されており 今後に向けた選択肢としてVue.js + TSの組み合わせは有力だと思っています。 Vue.js + TSで最も問題になるのは、公式のドキュメントがJSで書かれていることであり、 TSの書き方と若干サンプルコードが異なる という点です。これに関してはVue.jsに馴染みのあるメンバーがいれば大した問題にはなりませんが、全員がVueを初めて触るような場合には、いきなりTSを導入することには慎重になったほうがいいかもしれません(TSとJSはファイル単位で共存できるので後から追加することは難しくない)。 Storeをどうしているか Vue.jsではデータを一元管理するためのライブラリとしてVuexを使うのが一般的ですが、現状でのVuexはTSとの相性があまりよくなく、せっかくAPIレスポンスの型を定義したのにいざVueコンポーネントで取り出そうとすると型情報が失われてしまいます。そこでTSを活かすためにあえてVuexを採用せず、 GlobalEventBus のような構造を拡張した独自のStoreを使っています。この独自実装に関してはそのメリット・デメリットは以下のように現状では一長一短に感じています メリット TSの型をVueコンポーネント内部で利用して堅牢なコードを書ける シンプルな実装で可読性が高い デメリット 最低限の機能しか持たず、Vue.jsのエコシステムの流れからは外れる Vue.js devtools のVuexサポートが利用できない 後者のdevtoolsが使えない点に関しては、 公式の実装 を参考にして、storeの内部状態のダンプなど最低限のデバッグは可能にしています。 AtomicDesignに基づいた共通UIライブラリの構築 次世代管理画面プロジェクトと並行して社内のサービスで共通して利用するためのUIコンポーネントライブラリを構築しています。現在BASEでは Atomic Designを採用したデザインシステムの構築を進めており 、そのSketch上のデザインシステムと対応する形でStorybookを利用してコンポーネントライブラリを作っています。 storybook-addon-vue-info や @storybook/addon-knobs を利用して、メンバーがStorybookを見るだけでアプリを構築していけるように整備を進めています。 ブランチ単位での自動デプロイ このライブラリのリポジトリではブランチを切ってPRを作るたびにブランチ単位でStorybookがビルドされるようになっており、デザイナーとエンジニアの確認が簡単に行えるようになっています。 自前でUIライブラリを実装していく上での工夫・苦労 最初にコンポーネントを全部用意しようと考えない 一番小さいレイヤ(Atoms)のコンポーネントから作る コンポーネントだけを作ろうとせず、 実際に使いながらライブラリを育てる 特にformを構成するコンポーネントなど SketchのデータとStorybookのデータを一致させることにこだわりすぎない 見た目だけではわからないデザインの意図を拾ってStorybookに反映することを心がける 汎用的なコンポーネントを作るのは見た目の単純さに反して考慮することが多く、一発で作ろうとしてもなかなか作りきれません。有名なVueのUIコンポーネントライブラリの一つとしてVuetifyがありますが、その実装を見ても buttonのtsファイルが170行 、 inputで300行 あります。実際自分でコンポーネントを作っても、「あの機能がない」、「このカスタムができない」と問題が続々と出てきては一個ずつ対処する繰り返しになります。その状態で複雑なコンポーネントを用意しても、品質が上がらずコンポーネントの修正の足かせになりがちなので、小さなコンポーネントから我慢して作っていくことが必要だと感じました。 最後に BASEの次世代フロントエンド環境はまだ開発がはじまったばかりで、実際にはまだまだ課題が山積みです。次世代の管理画面も、UIコンポーネントライブラリも、自分の力で構築していってみたいというエンジニアを募集しているので、興味がありましたらぜひ一声かけていただければと思います。 open.talentio.com
アバター
こんにちは、BASE BANKでエンジニアをしている東口( @hgsgtk )です。 さていきなり本題ですが、2019年1月26日(土)に PHPカンファレンス仙台2019 が開催され、ネットショップ作成サービス「BASE」は、シルバースポンサーとして協賛しました。 大変盛り上がった最高のカンファレンスだったのですが、BASEからは、私と田中( @tenkoma )がセッションスピーカーとして登壇しましたので、それぞれの発表内容についてレポートいたします。 phpcon-sendai.net 発表資料 テストを書くのがつらくならないテスト駆動開発のアプローチ 私、東口( @hgsgtk )は、午前の最初の登壇で30分の発表をしました。 「テストがつらい」状況の様々な要因のうち、「テストを書くのが億劫」なことや「テストを書くのが難しいコードになる」といった要因にフォーカスを当て、それらに対してテスト駆動開発のアプローチを活用することで解決できないかという内容です。 ライブコーディング中の様子 当日は、ライブコーディングにてテスト駆動開発の流れを説明しました。 懇親会や後日Twitterなどで、感想や質問をいただけたのが大変ありがたかったです。 当日頂いた質問 テストを書くことに慣れてないと実際にやり始めるのに一苦労しそう 「テストを先に書く」という点について、テストを書くのに慣れていないと確かに難しいと思います。そのため、まずはテストを書くことに慣れるというのは前提として必要だろうという話をしました。 こちらについては、以前 PHPカンファレンス大阪2018 にて、 テストを書いたことがないエンジニアがテストを書けるようになるまでやったこと という発表しましたので、こちらの資料を参考にしていただくと良いかもしれません。 PhpStormとPHPUnitを連携してユニットテスト作成を楽にする 田中( @tenkoma )より、午後2つ目の登壇で30分の発表をしました。 PHPStormとPHPUnitを連携することでユニットテスト作成・実行を効率的に進めるというテーマで発表です。 発表中の様子 田中の個人ブログにて当日の発表の様子をレポートしておりますので、こちらも併せてご覧ください。 tenkoma.hatenablog.com 最後に PHPカンファレンス仙台2019 は今年初開催でしたが、良い意味で「初開催とは思えない」ほどしっかり運営されていて、とても楽しいイベントでした。 運営の皆様、素晴らしいカンファレンスをありがとうございました! 次はPHPerKaigi2019 次のカンファレンスは、3月29日〜3月31日に PHPerKaigi 2019 が開催されます。 BASEからは今回仙台で登壇した田中・東口が同じく登壇します。 田中からは、「 PhpStormでコードを理解する技術 」(レギュラートーク 15分)というテーマで発表します。 fortee.jp 東口からは、「 「質」の良いユニットテストを書くためのプラクティス 」(レギュラートーク 30分)というテーマを発表いたします。 fortee.jp また、ネットショップ作成サービス「BASE」は、ゴールドスポンサーとして協賛しています。 BASE株式会社 さま( @BASEec )から ゴールドプラン のお申込頂きました!ありがとうございます! https://t.co/Ezqw0Z0SiW #phperkaigi — PHPerKaigi 2019 @3/29-31 (@phperkaigi) February 1, 2019 ぜひ、皆さんPHPerKaigi 2019でお会いしましょう!
アバター
先週に引き続き、BASEでサーバサイドエンジニアをしている宮村です。 先日、負荷試験の取り組みについて紹介させていただきましたが、今回はその際に使用した Apache JMeter の活用について紹介させていただきたいと思います。 JMeterは高機能なツールなので使いこなすと強力ですが、少し複雑な機能のテストを行おうというとき、ややとっつきにくい部分もあるのではないかと思います(私はそうでした)。具体的な使い方をいくつか知っておくだけで、ぐっと便利に使えるようになると思いますので、これから負荷試験を行おうという方に少しでも参考になれば幸いです。 選定理由 負荷試験を行うツールはいくつかありますが、今回は下記の条件が満たせるものを探していました。 セッション管理できること ページ遷移を伴うシナリオが作成できること シナリオでレスポンスの値を取得して使えること 攻撃サーバがスケールすること 習熟コストが高すぎないこと これが満たされていれば、どれでもいいかな〜と思っていたので、以前少し使ったことがあったJMeterでできそうだと見えてきた時点でJMeterで進めることに決めました。 他に見たものを少しだけ紹介します。 Apache Bench:導入及び使用がとても簡単ですが、複雑なシナリオを扱うことができないため、カートの負荷試験には不向きであると判断しました。 Locust:JMeterと機能的には類似しているとのことで良さそうにも思いましたが、私個人にとってPythonでシナリオを書けることがあまりメリットにならないこともあり、選択しませんでした。 シナリオ作成 下記の手順で、シナリオを準備していきます。 テストケースの作成 作業PCへのJMeterの導入 記録コントローラでテストシナリオのベースを作成 実現したいテストシナリオへ改修 1. テストケースの作成 どのような高負荷状態を作りたいかを決めます。〇〇のページに、単位時間あたり〇〇のアクセスを、〇〇の時間発生させる、というようなものになるかなと思います。 これはツールによらない工程ですが、これがなければシナリオは作れません。今回は、過去の高負荷状態を再現できるようにケースを作成しました。 例)商品Aを1個、クレジットカードで購入するユーザが1分間に100人のペースで5分間来る、等(※数字はイメージです。) 2. 作業PCへのJMeterの導入 公式ページに従い、インストールを行います。 必要に応じてJavaのインストールを併せて行います。 (この工程の情報はWeb上にたくさんありますので、詳細は割愛させていただきます) 3. 記録コントローラでテストシナリオのベースを作成 シナリオ作成には「記録コントローラ」を使用しました。 JMeterをプロキシとして動作させ、ブラウザのプロキシ設定をJMeterに向けることで、ブラウザでの操作をJMeterで記録する機能です。 これを使えば記録したシナリオをそのまま使用できるはずでしたが、いくつかのパラメータが欠けていたので補ったり、不要なシナリオを削除したりといった作業が必要でした。 ただ、この修正の工程が必要であったとしても、記録コントローラを使うメリットは大きいと感じましたのでおすすめです。 4. テストシナリオの改修 1で決めたテストケースを実現できるよう、各種の設定値を書き加えたり変更したりします。 今回は、たとえば商品IDなどのいくつかのパラメータは変数として定義するなど、必要に応じて記録されたシナリオに改修を加えていきました。 ここで、便利だったエレメントを以下に紹介します。 便利だったエレメント8選 ユーザ定義変数 手元の環境でシナリオを作成し、試験環境にで実行するということをしたので、urlなど環境固有の値を簡単に切り替える必要があり使用しました。 HTTP認証マネージャ basic認証をかけた環境で試験をするのに使用しました。 HTTPクッキーマネージャ セッションを利用するので使用しました。 異なるユーザの購入を想定したので、「繰り返しごとにクッキーを破棄する」設定にしました アサーション 各リクエストで、レスポンスコードは問題ないが、期待するレスポンスが返らない場合にテストを失敗させるため使用しました。 具体的には、正しく次の画面に遷移した場合と、エラーで同じ画面にとどまっているにもかかわらずレスポンスコードは正常な場合を区別したい場合に使用しました。 HTMLリンクパーサ 正規表現抽出 前の画面で生成した値を、後続のリクエストのパラメータとして使う場合に使用しました。 はじめは後述のHTMLリンクパーサを使っていたのですが、JMeterサーバを複数台構成にして、リモート実行した際に正常に動作しないことがあったため、正規表現抽出に切り替えました。 統計レポート シナリオ実行の様子を眺めるのに使いました。 JMeterには様々な高機能なリスナがあり便利なのですが、リクエスト数を増やした場合に、リスナの処理が重くなってしまうそうです。それを避けるため、これとシンプルデータライタの2つだけを実際の試験実行時には使用しました。 シンプルデータライタ シナリオ失敗の具体的な状況を調査するため、結果はすべてCSVファイルに書き出しました。 リクエスト失敗の原因調査等、必要に応じてExcelで調査しました。 完成したシナリオの例 実行 シナリオ実行 AWS上のWindowsサーバ1台にJMeterを設置し、少ないリクエスト数から徐々に負荷をかけていきました。 最初は、シナリオや設定値の妥当性の確認も兼ねて、1リクエストから実行していきます。 リクエスト数を増やす過程で、JMeterサーバがボトルネックかな?というタイミングでリモート(Linuxサーバ2台)で実行するように変更しました。 socket write error, failed to respond, closed connection というエラーが、シンプルデータライタで取得したログに出力されたタイミングがそれです。 結果の記録 どういうシナリオを流したか、結果はどうだったかをスプレッドシートに都度記録しました。「実験ノート」をとる要領で、下記のような内容を都度記録しておきました。これが後に結果レポートになっていきます。 リクエストの種類 成功数、失敗数 シナリオ完了までの時間 成功はしているが遅延している、を検知 実行時刻 各種ログを後から調査するため まとめ フォームの入力やセッションを利用し、複数画面の遷移を伴う機能であるカート機能の負荷試験を、JMeterを使うことで実施できました。 ツールの選定には、試験でどういった機能が必要かをまず明確にするのが重要でした。 シナリオが資産として残っているので、今後も改善しながら負荷対策に役立てていく予定です。 最後に 本番相当の環境でのパフォーマンス改善に興味のある方、これからもさらなる改善を行っていくことになると思いますので、ぜひご連絡ください! open.talentio.com
アバター
BASEでサーバサイドエンジニアをしている宮村です。 つい最近まで、主にEコマースプラットフォーム「BASE」の決済領域の開発をしていました。決済領域は、いかなる場合でも安定稼働が求められる領域です。いかなる場合でもというのは、BASEが対応する各種決済方法やクーポン、 ショップコイン など機能の組み合わせという意味でもそうですが、アクセス集中による高負荷に対しても、同様に安定が求められます。 前者に対しては、弊社東口から ユニットテストの取り組み を以前紹介させていただきました。今回は、後者への取り組みとして、負荷試験の取り組みを紹介させていただきたいと思います。 動機 「BASE」は「Eコマースプラットフォーム」ですので、主として提供している機能の一つに、「カート」の機能があります。主として提供しているということは、サービス開始当時から、この機能を提供させていただいているということでもあります。 リリースした頃のBASE おかげさまで多くのショップ様、購入者様にご利用いただけるようになり、その性能面について把握、改善することがこれまで以上に求められる場面が出てきました。 改善するためには、改善したことが評価できなくてはいけません。購入に関する定量的な指標をおいて、計測することにしました。 準備 環境 前提として本番相当のものを用意することにしました。いくつかの懸念があったのですが、下記のようにクリアすることができました。 1. コスト面の課題 使うときだけ簡単に試験環境を立ち上げられる仕組みを作ったり、関連している諸サービスのうち今回のシナリオで必要なものだけを本番相当にするなど、コストを抑える工夫をしました。 2. 外部サービスとの連携 カートシステムでは、外部の決済サービス等との連携を行っています。負荷試験といっても、外部サービスへの過負荷は望ましくありません。(サービスによっては許可されない場合もあります。)今回は内部の性能試験にフォーカスしたかったこともあり、外部サービスを模したモックサービスを構築してそこに接続するようにしました。 また、試験中の状況の把握や、発生した異常の解析のため、監視サービス等も、本番同様のものを導入しました。 ツール 試験ツールには、諸条件を考慮して Apache JMeter を使用しました。 セッション管理やページ遷移を伴うシナリオが必要だったこと、負荷テストサーバーのスケールが容易にできること、メンバーの経験などを考慮してツールの選定を行いました。(JMeterの活用については、別の記事で述べられればと思います。) 結果として、機能や習熟の不足などによる大きな問題もなく、試験を行うことができました。 シナリオ カートに商品を投入してから、購入者情報の入力、購入完了までの数画面を遷移するものとしました。カート内は購入者情報など入力される値も多いのですが、JMeterの「記録コントローラ」を使用することで比較的手をかけずにシナリオを作ることができました。 実施 役割分担 今回の負荷試験は、主として3名のエンジニア(アプリケーションエンジニア2名、SRE1名)で進めました。 シナリオ構築やモックサービスの構築、シナリオ実行、レポーティングなど、主にアプリケーションに関する部分をアプリケーションエンジニアが担当し、環境構築などの部分を、SREが担当しました。 それぞれがやるべきことに集中できたことで、環境構築の工夫やモックサービスの構築などプラスアルファの部分にも力を割くことができたことはとても良かったように思います。 さて実行 シナリオを実行してみると、いくつかの課題が発生しました。 モックサーバがボトルネックになっていた! これは元々、様子を見ながら調整する予定でした。LBとappサーバのログを確認し、接続数を増やして安定しました。 SREのメンバーがここをサッと見てボトルネックを特定してくれました 購入ではないところがボトルネックになっていた! 当初のシナリオでは、まず商品画面にアクセスして、カートに商品を投入するということをやっていたのですが、商品画面に使っている外部サービスが開発用のスケールのものでした。今回のシナリオでは不要なアクセスだったため、本当に必要な画面遷移に絞ることで解決しました。 New Relicで、遅くなっている処理を特定しました 想定したところと違うボトルネックが発覚した! DBがボトルネックになるかな?と想定していたところ、Apacheがボトルネックになっているような挙動を見せました。どちらも本番相当の環境であるため、当初想定していた負荷の強度をクリアしていたこともあり、このあたりが限界であると結論づけました。いくつかの設定を変更して追加の試験を行い、即座に反映できるような変更点は見つけられませんでしたが、次の改善への取り掛かりとして知見が得られました。 Mackerelで監視 DBエンジニアの 植木 に教えてもらったRDSのPerformance Insightsがとても便利でした 実施中の様子 Slackで実況しながら、わいわいやりました。 負荷を増やしていきながら、エラーなく処理を完了している様子や、謎のエラーが発生していることを随時報告するようにしました。隣の島のリードエンジニアがさっくりと原因を指摘してくれたり、SREのメンバーがインフラを調整してくれたり、次々に現れる課題が攻略されていくさまに感動と感謝でいっぱいになりました。 結果 負荷試験を実施すると決めてから2ヶ月程度で結果を出すところまで行うことができ、定量的なレポートを社内に共有できました。 また、並行して進めていた改修についても、前向きな効果がありそうだという結果も得ることができました。 トラブル以外では決済領域が目立つことは少ないのですが、前向きな成果を共有できたことは、チームにとっても良かったなと思いました。 まとめ 負荷試験を実施することで、システムの性能について定量的な指標を得ることができました。 性能に関する改善を行うにあたり、その効果が見込めることを改修前に示すことができました。高負荷状態は常に発生するものではないので(残念ながら)、同等の環境で再現させることで、その効果や副作用がないことを確認したうえでリリースの判断をすることができました。 高負荷状態を再現させる環境を手に入れたことで、安心してサービスを成長させていく土台ができたかなと思います。他の箇所で高負荷に起因する課題が発生した場合にも、知見と環境を活用して対応していけるものと期待しています。 最後に 本記事では、BASEで実施した負荷試験の取り組みについて紹介させていただきました。負荷試験に取り組むにあたり、特定のツールの使い方以上の実践的な情報がまだ少ないなと感じるところもあり、一つの実践例として本記事が少しでも参考にしていただければ幸いです。 また、本文では簡単な紹介になってしまいましたが、JMeterの活用やモックサーバの構築については今後別の記事で紹介できればと思います。 BASEでは60万ショップの決済を支えるエンジニアを募集しています。支えるだけでなく、より良い決済システムにしていく挑戦をやっていきますので、興味のある方はぜひ下記よりご連絡ください! open.talentio.com
アバター
あけましておめでとうございます。 BASE BANK株式会社 でソフトウェアエンジニアをやっている東口( @hgsgtk )です。 2018年末から年明けにかけて、EKSが東京リージョンに来たりAWSからのリリースが賑わいを見せていますが、その中から、 AWS Fargate の次の新機能を実際のプロダクトに適用しました。 AWS Fargate プラットフォームバージョン 1.3 でシークレットのサポートを追加 これを期に、コンテナアプリケーションにおける設定情報を扱う考え方・それを実現するためのAWSのサービス構成と得られた利点についてまとめてみようと思います。 目次 設定情報の扱いに対する要件 コンテナベースの設計思想・原則 ECS(Fargate)を用いる場合の設定情報の扱い方 設定情報の扱いに対する要件 開発背景 BASE BANK社では、即時に資金調達ができる金融サービス「 YELL BANK(エールバンク) 」というプロダクトを開発しています。 以前本ブログに投稿した「 GoのAPI開発現場におけるユニットテストTips 」 や「 Goを運用アプリケーションに導入する際のレイヤ構造模索の旅路 | Go Conference 2018 Autumn 発表レポート 」の通り、Go言語でアプリケーションを開発しており、docker buildしたイメージから作成したコンテナをECS(Fargate)上で動かすことで機能を提供しています。 設定情報とは 本記事内での「設定情報」は、データベース、Memcached、他バックエンドサービスなどのリソースハンドルのための 認証情報 を指します。これらは、本番・ステージング・開発・QAなど環境ごとにそれぞれ異なる値を持つ属性があります。 コンテナアプリケーションの設計として、設定情報をどう取り扱っていくか次に考えていきます。 コンテナベースの設計思想・原則 コンテナベースで動かすアプリケーションでの設計思想について次の2点の資料がよく参照されます。 Beyond the Twelve-Factor App Principles of container-based application design (Redhat) この2つの資料からコンテナベースアプリケーションにおける設定情報の扱い方について見ていきます。 Beyond the Twelve-Factor App 2012年に、モダンなクラウドアプリケーションのベストプラクティス「 The Twelve-Factor App 」をHerokuの中の人が書きました。Beyond the Twelve-Factor Appは、2016年に Pivotal 社が、オリジナルのガイドラインのアップデート・ガイドラインの追加したものです。 クラウド環境を活用したクラウドネイティブアプリケーションの新たなベストプラクティスをガイドラインとしてまとめてくださっています。次のURLから実際にPDFをダウンロードすることができます。 content.pivotal.io また、次のスライドが大変わかりやすくガイドラインについてまとめてくださっているので、そちらもご参照いただくと良いかと思います。 Chapter 5 Configuration, Credentials and Code この資料内で、特に設定情報については、 Chapter 5 Configuration, Credentials and Code という章で言及されています。ピックアップすると大きく次の内容です。 設定や認証情報は コードから分離 すべき 環境は無限に増えていくため、環境(dev, prd...etc)ごとに設定をグルーピングすべきではない。 設定をコードから分離する一番の方法は 環境変数 への格納である。 設定情報とコードを分離することを求めており、分離できているかどうかの指標として、 今すぐにでもコードをオープンソース化できるか を上げています。 次にもう一つredhatが公開している設計原則について見てみましょう。 Principles of container-based application design (Redhat) redhatが公開しているホワイトペーパーで、コンテナベース・アプリケーションの設計原則についてまとめています。 次のURLにて日本語版の資料をダウンロードすることができます。 www.redhat.com IMAGE IMMUTABILITY PRINCIPLE (IIP) イメージ不変性の原則 いくつかの原則を説明している中で設定情報についての扱いに関連のあるものとしてこちらの原則があります。 コンテナ化アプリケーションは不変であるため、ビルドされた後、異なる環境間で変化することは想定されていません。つまり、環境ごとにコンテナの作成や修正を行うのではなく、ランタイムデータの保存に外部手段を利用し、外部化した設定を環境によって使い分けます。 上記の記述により、yamlファイルなどでアプリケーション内で設定情報を分けてそれぞれビルドする方法ではなく、ビルドするアプリケーション内に環境によって異なる情報は入れず、外部に保存した設定情報を使用することが推奨されています。 2つの思想・原則から方針を見出す これまで見てきた2つの資料から、 コードから設定情報を分離し、環境変数から外部設定した設定情報を注入する 構成としていきます。 ECS(Fargate)を用いる場合の設定情報の扱い方 設計方針が決まったところで実際に AWS 、特に ECS(Amazon Elastic Container Service) を利用した場合の設定情報の扱い方についてです。 概要構成 概要構成は次のようなものになります。 概要構成 以下、 AWS Fargate プラットフォームバージョン 1.3 でシークレットのサポートを追加 で発表された機能を利用するため、プラットフォームバージョンは 1.3以上 を前提とします。 アプリケーション 環境変数から設定情報を取得する実装とします。例えば、Go言語の場合はosパッケージを利用して次のようなコードを書くことになるでしょう。 dbHost := os.Getenv( "DB_HOST" ) ビルドしたアプリケーションのコンテナイメージは、 ECR(Amazon Elastic Container Registry) や Docker Hub といったコンテナレジストリサービスにpushします。 設定情報の保存 設定情報は、 SSM(Systems Manager) Parameter Store に保管していきます。 SSMでは、パラメータを階層的に管理する事が可能です。 docs.aws.amazon.com 具体的には、 /stage1/stage2/stage3 といった形で階層を掘っていく形になります。 この際、DBのパスワードなど暗号化して保存したい場合は、 KMS(Key Management Store) を用いて暗号化キーを作成し、そのキーを持って暗号化します。 SSMに設定する情報を暗号化する際は登録時に暗号化オプションを付け、KMSキーを指定します。 aws ssm put-parameter --name /goecssample/database/sample/master/password --type "SecureString" --value "password" --key-id "< KeyId >" --description "データベースのmasterユーザーパスワード" --region ap-northeast-1 具体的には、typeを SecureString とし、key-idに作成したKMSキーを設定するだけです。 コンテナから設定情報を利用 SSMに保存した設定情報を、コンテナに挿入するためには タスク実行ロール に対してSSMのパラメータ取得・KMSキーでの復号を許可する必要があります。 具体的には、タスク実行ロールに対して以下のようなポリシーを追加します。 { " Version ": " 2012-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Action ": [ " ssm:GetParameters ", " kms:Decrypt " ] , " Resource ": [ " arn:aws:ssm:region:aws_account_id:parameter/parameter_name ", " arn:aws:kms:region:aws_account_id:key:key_id " ] } ] } タスク定義 ECSのプラットフォームバージョン1.3.0より前、Fargateを利用している場合、System MangerのParameter Storeなどから設定情報をコンテナに注入するには、自前でdocker-entrypoint.shなどからSSMに対してAPIアクセスして取得する必要がありました。 しかし、今回のサポートによって、タスク定義内のコンテナ定義に設定することによって、コンテナ起動時に自動でコンテナに対して設定を注入することができるようになりました。 具体的には、コンテナ定義の環境変数に、環境変数名・SSMのパラメータ名を指定するだけです。 コンテナ定義/環境変数設定 1.3より前は、次のようなentrypoint.shなどを書いて対応していました。 #!/usr/bin/env bash set -e export DB_HOST=$(aws ssm get-parameters --name /prd/database/host --query "Parameters[0].Value" --region ap-northeast-1 --output text) exec "$@" 1.3へのアップデートによって、自前での実装が不要になり、かなりシンプルになりました。 その他 その他、より詳細の説明は、AWS公式の次のドキュメントを参照してみてください。 docs.aws.amazon.com この構成にして得られた利点 コードから設定情報を分離できた コードから設定情報を分離したことによって、全アプリケーションエンジニアがすべての設定情報を参照できる状況は避けることができました。 加えて、設定情報は、 AWS Systems Manager Parameter Store に設定されています。 本番・ステージングなどでアカウント自体が分かれている場合は、そもそもアカウントを発行されている人のみに閲覧を絞ることができ、加えてIAMの設定等で誰のアクセスを許可するかを制御することが可能になりました。 設定の量が増えても階層的に扱える AWS Systems Manager Parameter Store では、階層的にパラメータを登録することが可能なため、情報を階層的に扱いたいモチベーションもある程度満たしてくれました。 シークレットのサポートによって得られた嬉しいこと AWS Fargate プラットフォームバージョン 1.3 でシークレットのサポートを追加 によって嬉しかった点も記載します。 コンテナ起動時の複雑性が軽減された 当初、デプロイ時の複雑性を増していたdocker-entrypointでの自前実装が不要になり、アプリケーションの複雑性が減りました。 イメージサイズが小さくなった 副次的な効果として、AWSのAPIに対するアクセスが不要になったため、実行イメージに含めていた python と aws-cli が不要になりました。 その効果によって、 約40MB程度だったイメージサイズが約10MBまで小さくなりました。 まとめ そもそも、コンテナアプリケーションをどう扱うべきなのかという観点から、実際にAWS Fargateを利用した場合についての説明をさせていただきました。 当初扱いづらさがあった部分もアップデートによって日々使い勝手がよくなってきている印象を覚えています。 現在、ECSなどでアプリケーションを構成しようとしている・または検討している方にとって、一つの参考になれば幸いです。
アバター
この記事は「BASE Advent Calendar 2018」25日目の記事です。 devblog.thebase.in こんにちは。BASEでFrontend Groupに所属している 三佐和 です。主にネットショップ作成サービス「BASE」のフロントエンドを担当しています。 先日デザイングループのマネージャー早川が 「BASE」の管理画面リニューアルプロジェクトのこれまでとこれから で話しているように、現在BASEでは本格的にフロントエンドをVue.jsで置き換えるプロジェクトが進行しています。 これまでのBASEのフロントエンドは、主にマークアッパーを含むデザイナーが中心になってjQueryでゴリゴリと実装していました。 Frontend Groupが発足したものの、まだまだこれからで、しばらくはデザイナーと協力してサービスを作っていくスタンスで開発を進めています。 そのため、モダンなフロントエンドの考え方や新しく導入されたシステムについて、デザイナーの方へ伝えたり、慣れてもらうことの重要性が高まっていました。 しかし、当初はこんな声もありました。 そこで、Frontend Groupとして、主にデザイナー向けにVue.js勉強会を開催することにしました。 また、少し前に流行した短期集中型エクササイズ・Billy's Boot Campから、この勉強会のタイトルを「Vue Boot Camp」と名付けました! このブログでは、それを開催する過程で伝えたかったことや考えていたこと、準備したことを紹介していけたらと思います。 対象を考える BASEの場合は主に以下の3種類のロールが「デザイナー」と呼ばれています。 いわゆるマークアッパーで、jQueryを使ったフロントエンドコーディングができる UIデザインができて、HTMLとCSSでそれを表現できる UIデザイン、ビジュアルデザインの専門で実装はほとんどしない このうち今回対象にしたのは、上の2つで、前提としてある程度HTMLとCSSのことは分かっている、ということをラインとしています。 これらの条件に当てはまる人は一旦Vue.jsにはまったく触ったことがない人、と仮定しています。 覚えてもらいたい・知ってもらいたいこと 対象を絞ったので、次に覚えてもらいたいことを考えていきます。 「デザイナー」と呼ばれる方にフロントエンドで責任をもってもらいたい部分は、主に以下の2つだと考えました。 大まかなシステムが構成されている上での、デザイン当て、マークアップ、インタラクションデザイン 自社開発のコンポーネントのメンテナンス これらを実現する為にVue.jsやモダンフロントエンドに関する知識の中でも、この要素は伝えたい!というのが Web Componentsという考え方 BASEで利用している基本的なフロントエンド構成 自社開発のコンポーネントを実際に利用した開発を体感してもらう css-moduleを使ったスタイリング フロントエンドにおける簡単なCRUD操作 これらであるとして題材を考えることにしました。 題材を考える 前半はVue.jsのチュートリアルをなぞりつつ、BASEの新しいフロントエンドやWeb Componentsな考え方に触れてもらう、というところまではすぐに決まりました。 後半は、なにか一つアプリを作る体験をしてもらいたいと考えていました。 これらを満たせるアプリを考えたときに、JavaScript界隈ではおなじみ(?)の TodoMVC というものを紹介してもらいました。 これをベースに考えていくと上記のような要素が満たせそうだったので、これをアレンジしたTodoアプリを今回の題材にすることにしました。 これに対し、実際にどのようなアレンジをしていったかというと... 自社コンポーネントを使った開発 BASEではBBQという名のUI実装時に使用されるコンポーネントのライブラリがあり、例えばVue.jsのサンプルでは以下のようなコードになっていますが、 < ul class = "todo-list" > < li v- for = "todo in filteredTodos" class = "todo" :key= "todo.id" : class = "{ completed: todo.completed, editing: todo == editedTodo }" > < div class = "view" > < input class = "toggle" type = "checkbox" v-model= "todo.completed" > < label @dblclick= "editTodo(todo)" > {{ todo.title }} </ label > < button class = "destroy" @click= "removeTodo(todo)" ></ button > </ div > //... </ li > </ ul > このようなリストに含まれるチェックボックスや削除ボタンのコンポーネントをBBQを使って書くと以下のように書くことができます。 < ul : class = "$style.todo" > < li : class = "$style.todo_list" > < bbq-checkbox : class = "$style.todo_checkbox" > < template slot= "text" > {{ item.text }} </ template > </ bbq-checkbox > < bbq-icon- button : class = "$style.destroy" icon= "crossCircle" noBorder @click= "removeItem" ></ bbq-icon- button > </ li > </ ul > このような変更を全体的に行うことで、それぞれをBBQを使って実装することを体験してもらうことができます。 css-moduleを使ったスタイリング またcss-moduleを使った実装に置き換えて .vue ファイル内にスタイルを書くことで、そのコンポーネントの中でしか影響を与えないCSSを作ることができます。 < div : class = "$style.hoge" > {{ message }} </ div > < style lang = "scss" module> // スタイルを書く .hoge { //... } </ style > 事前に準備したこと テンプレートプロジェクトの作成 デザイナーの人にwebpackの設定をしてもらいたいわけではないので、BASEで実際に使用している構成と近い形になるよう、事前に以下のような設定を行ったプロジェクトを準備しました。参加者は git clone と yarn install を行うだけで、すぐに Vue.jsでの開発が始められます。 一般的なwebpackの設定などは割愛しつつ、特に重要なポイントのみ列挙します。 必要なパッケージをインストール yarn add -D webpack webpack-cli webpack-dev-server yarn add vue yarn add -D typescript ts-loader vue-class-component yarn add -D vue-loader vue-style-loader vue-template-compiler yarn add -D css-loader sass-loader postcss-loader webpackを設定 TypeScript、シングルファイルコンポーネント、css-moduleが使えるよう設定します。 module: { rules: [ { test: /\.tsx?$/ , use : { loader: 'ts-loader' , options: { appendTsSuffixTo: [ /\.vue$/ ] , } } } , { test: /\.vue$/ , loader: 'vue-loader' , options: { loaders: { 'scss' : 'vue-style-loader' , 'sass' : 'vue-style-loader' } } , exclude: /node_modules/ } , { test: /\.[s]?css$/ , use: [ 'vue-style-loader' , { loader: 'css-loader' , options: { modules: true } } , { loader: 'postcss-loader' } , { loader: 'sass-loader' } ] , exclude: /node_modules/ } ] } シングルファイルコンポーネント用の型定義を追加 拡張子が .vue となっているSFCのファイルをimportするときに、記述されているコードをTypeScriptとして認識できるようにする必要があります。このために以下のような型定義ファイルを作成します。 declare module '*.vue' { import Vue from 'vue' export default Vue } ドキュメントの用意 Vue.jsの公式ドキュメントとは別にBASEの構成で表現するための対応の説明と、順を追って TodoListを作成していくドキュメントを用意をしました。 全体の進行をこれにあわせることで当日参加していない方でも、このドキュメントを上から追っていくとだいたい理解できるようになっています! 当日の様子 そんなこんなで迎えた勉強会当日 Vue.jsを独学で勉強し始めたメンバーやバックエンドエンジニアなど、デザイナー以外もたくさん参加してくれました! 反省と感想 開発環境作りやドキュメントを作りながら、どのような順序でチュートリアルを進め、どのような説明をどのタイミングで伝えたらVue.js初学者にとって分かりやすい勉強会になるかを考えて準備を進めてきました。 実際にVue Boot Camp当日を迎えてみると、進行していくことに精一杯で、参加メンバーの進捗具合など見れない部分が多かったのですが、Frontend Groupのメンバーがフォローに回ってくれたり、Vue Boot Camp専用のSlackチャンネルの中で、参加メンバー同士で参考となるリンクや追加の課題を共有し合ったり、とサポートしてくれたおかげで会を円滑に進めることができました。 参加者の感想のコーナー 楽しかったです!追加の課題なんかも丁度良い難易度に感じました。 第二回目があれば是非参加したいと思います。 題材がちょうど良かったです。 ある程度人集まってしたので色々フォローしてもらったり解説してもらったりすごく有意義でした。 業務でそれなりに使ってる方だったのでまあまあ自信もって臨みましたが、改めてこうやってステップバイステップでやっていく中で、結構基本的なところで理解できてなかった点が色々と発見できたので非常に良い機会でした! このような声をもらうことができたので、第二回目も開催できたら、と思います。 また、今回の記事がBASEアドベントカレンダーの最終日ということで、今までに公開された記事の一覧をご紹介します! 日付 タイトル 12/1(土) エンジニアとしてワクワクし続けるためのエンジニアリングマネージャという役割分担 12/2(日) 君は GitHub の Suggested change を知っているか? 12/3(月) 新任エンジニアリングマネージャ(私自身)を支えてくれた本と言葉 12/4(火) GoのAPI開発現場におけるユニットテストTips 12/5(水) BASE で使っているPHPフレームワークにプルリクエストを送ろうとしたら、先を越された話 12/6(木) 分位点回帰を使って、「その回帰予測どれぐらい外れるの?」を説明する 12/7(金) Abstractを用いたデザイン管理システムを導入して1年経ったお話 12/8(土) 「BASE」の管理画面リニューアルプロジェクトのこれまでとこれから 12/9(日) SQLアンチパターンとBtreeインデックスの関連性 12/10(月) 初めてでも実践できる、挫折しないテックブログ運営~半年間更新0→30本公開しました~ 12/11(火) BASE株式会社を6年間経営して感じた学び 12/12(水) BASEがもっと好きになる。鶴岡さん観察日記 12/13(木) テストを書くモチベーションを上げるための、カバレッジレポート活用方法 12/14(金) デザイナーの私が初めてプロダクトのコードをコミットしてみた! 12/15(土) 日本のパパに、育休のススメ~私の育休体験記~ 12/16(日) デザイン表現が広がる、Lottieアニメーション 12/17(月) グロースハックとディレクションとAndroid開発を経験した1年の振り返り 12/18(火) Data Strategy GroupのAPI開発の挫折とその後 12/19(水) 国内2019年のFinTechトレンド予想(融資・資金調達・ファイナンス領域編) 12/20(木) クラスタリングで時系列予測はできる? 〜Twitterの株価を予測してみた〜 12/21(金) 「Sketchを用いたデザインシステム」を作ってチームでのデザイン作業を効率化した話 12/22(土) ボドゲ最強説 ~BASEボードゲーム部のご紹介~ 12/23(日) BASEのプロダクトマネージャーが大切にしている3つのこと 12/24(月) Goによる静的解析入門 それではみなさん、良いお年を!
アバター
この記事は「BASE Advent Calendar 2018」24日目の記事です。 devblog.thebase.in はじめに BASEでエンジニアとしてインターンをしている池田です。今日はクリスマスイブということで、以前から気になっていたグリューワイン(ドイツのクリスマスに欠かせないホットワイン)をクリスマスマーケットに飲みに来ています。 普段は BASE BANK というBASEの100%子会社にて金融事業の立ち上げを行っています。BASE BANKのプロダクトのAPIはGoを使って書かれているのですが、BASEでのGoの使用はこのプロジェクトが初だったので、開発基盤整備の一貫で様々なlinterの導入を行いました。その際にlinterの内部がどうなっているかに興味を持ち、すごく簡単なlinterの仕組みを実際に作ってみたので、今回はその知見をお話しします。 Goと静的解析 Goには、標準パッケージとして静的解析を行うための go パッケージが存在します。 また何よりGoは文法がシンプルな静的型付け言語なので、静的解析をとても簡単に行うことができました。 今回はその中でも、字句解析を行う go/token 、構文解析を行いAST(abstract syntax tree: 抽象構文木)を取り扱う go/ast や go/parser パッケージを用います。 今回は、 megacheck というlinterを用いた際に実際に注意された、 bool値で条件分岐するときは、 if x == false {...} じゃなくて if !x {...} の方がいい といったことを検出してみたいと思います。 今回の静的解析の簡単な流れを下図に示します。 抽象構文木のノードを探索していき、条件に当てはまるものがあったら警告するといった感じです。 やってみる では実際にコードを見ていきましょう。 下がコード全体です。少しずつ解説していきます。 func main() { // 指定したファイルの構文解析を行う fset := token.NewFileSet() f, err := parser.ParseFile(fset, "sample.go" , nil , 0 ) if err != nil { log.Fatal( "Error:" , err) } // 抽象構文木を探索する ast.Inspect(f, func (n ast.Node) bool { // 二項演算子ではない場合は無視 expr, ok := n.(*ast.BinaryExpr) if !ok { return true } // == の場合 if expr.Op == token.EQL { xIdent, ok := expr.X.(*ast.Ident) // Expr型をast.Ident型に型アサーション if !ok { return true } yIdent, ok := expr.Y.(*ast.Ident) // Expr型をast.Ident型に型アサーション if !ok { return true } // 識別子を文字列として取り出す xString := xIdent.String() yString := yIdent.String() switch yString { case "true" : fmt.Printf( "- got: %s == %s \n + want: %s \n " , xString, yString, xString) case "false" : fmt.Printf( "- got: %s == %s \n + want: !%s \n " , xString, yString, xString) } return true } return true }) } ファイルの読み込みと構文解析 // 指定したファイルの構文解析を行う fset := token.NewFileSet() f, err := parser.ParseFile(fset, "sample.go" , nil , 0 ) if err != nil { log.Fatal( "Error:" , err) } まずは sample.go というファイルを指定して parser.ParseFile により構文解析を行います。 package main func sample() { isAvailable := false if isAvailable == false { return } } ここで、「あれ、まず字句解析しないの?」と思った方もいらっしゃるかもしれません。 実は go/parser パッケージが 内部で字句解析を行うため、直接字句解析を行うことはあまりない のです。 抽象構文木の探索 続いて、構文解析した結果により作られた抽象構文木を扱います。 // 抽象構文木を探索する ast.Inspect(f, func (n ast.Node) bool { ... } ) ast.Inspect は抽象構文木のノードをトラバースする関数です。この中の func(n ast.Node) bool { ... } で、抽象構文木の各ノードに対して一律の処理をかけます。 実際にどのような処理をするか見ていきましょう。 // 二項演算子ではない場合は無視 expr, ok := n.(*ast.BinaryExpr) if !ok { return true } まずは ast.Node 型のノードを ast.BinaryExpr 型に変換しています。 ast.BinaryExprは + や == などのような二項演算子を表す型です。今回は x == false のような箇所を検出したいので、この型に変換できない場合は無視して次に進みます。(なぜ最初にast.BinaryExp型に変換できるノードを探しているのかは下で説明します) ast.BinaryExpr は以下のような構造体です。 type BinaryExpr struct { X Expr // 左のオペランド OpPos token.Pos // オペレーターの位置(ファイルの何行目の何バイト目か) Op token.Token // オペレーター Y Expr // 右のオペランド } また下図は二項演算を抽象構文木にした場合の図で、BinaryExpr構造体のフィールド(X, Y, Op)との対応が見て取れると思います。 図を見てわかる通り、二項演算では演算子が親ノード、オペランドが子ノードになるため、このステップではまずast.BinaryExp型に変換できるノードを探していました。 続いて、上記の結果返ってきたast.BinaryExp型の値に対して処理をかけます。 // == の場合 if expr.Op == token.EQL { xIdent, ok := expr.X.(*ast.Ident) // ast.Expr型をast.Ident型に型アサーション if !ok { return true } yIdent, ok := expr.Y.(*ast.Ident) // ast.Expr型をast.Ident型に型アサーション if !ok { return true } // 識別子を文字列として取り出す xString := xIdent.String() yString := yIdent.String() switch yString { case "true" : fmt.Printf( "- got: %s == %s \n + want: %s \n " , xString, yString, xString) case "false" : fmt.Printf( "- got: %s == %s \n + want: !%s \n " , xString, yString, xString) } return true } 今回は簡単に x == y のような部分だけ検出したいので、まずオペレーター Op が token.Token 型の == と等しいか調べています。 そしてオペレーターが == だった場合に、次は各オペランドを ast.Ident という型に変換しているのがわかるかと思います。 ここでIdentが何かというと、 識別子 を表します。 上図のように、字句解析のあとの変数名や関数名、bool値は識別子を表す ast.Ident 型、 1 や "dog" など数値リテラルや文字リテラルは ast.BasicLit 型になります。 今回はある変数をboolと比較している箇所を評価したいため、その条件に合致するようなオペランド対を探しています。 あとは、該当するような箇所があったらその旨を出力して終わりです。 実際に sample.go にこのlinterをかけた結果を見てみましょう。 # go run main.go - got: isAvailable == false + want: !isAvailable ご覧のように、 sample.go 内でbool値と直接比較している箇所を検出できています。 終わりに 今回は、標準の静的解析パッケージである go パッケージを使って簡単な静的解析ツールを試作してみました。 go パッケージを使えば、lintの他にもコードの自動生成や自動フォーマットをすることもできます。 またこのパッケージのソースコードを読むことでコンパイラや言語処理系の勉強にもなるので、静的解析はGoの中でも面白いトピックの一つなのではないでしょうか。 では、よいクリスマスをお過ごしください!
アバター
BASEの執行役員/Product Managerをしている神宮司( 7jin16 )です。 BASEのプロダクトマネージャーは、プロダクトの戦略、製品、事業数値まで責任を持ちます。 ユーザーの方々にどうしたら素晴らしい体験を届けることができるのかを悩みながら毎日淡々と会社全体でプロダクトを作っているため、プロダクト作りでとても重要だと思うことを書いていきます! ポエムを書く 新プロダクトや新機能を作り始める前に実現したい理想の世界観についてのポエムを書くことが多いです。ポエムはあくまで Be Hopeful に書きます。深夜に書くとより叙情的に書けるのでオススメです。 ポエムを書くことによって自分たちが目指したい方向性が言語化されて、新プロダクトや新機能のコアバリューが設定されます。コアバリューが設定されていれば、タスクの優先順位が付けやすくなります。 ポエムによってチームもエモい気持ちで頑張ることが出来てテンションが上がります。  優先順位の設定 施策の優先順位決めは、めちゃくちゃ大切です。すべての力を優先順位決めに使った方がいいんじゃないかと思うほど、超大切です。 プロダクトを作っていると、様々な目線でのフィードバックがありプロダクトの改善施策案はめちゃくちゃ出てきます。しかもサイズ感も改善される箇所も様々です。しかし時間は有限です。プロダクトマネージャーは常に効率的にユーザー体験を改善して事業数値、そして世の中にインパクトを与えていかなければなりません。 その中で適切に優先順位を設定していくのは難易度が高いです。 施策の優先順位を設定するときは、以下の3つを並べて考えます。 リリースまでの時間軸(工数) 改善が期待できる効果(数値) 改善することによって積み上がる施策か リリースまでにどれくらいの時間が必要か、これが短ければ短いほどより多くの改善を行うことができ、改善が期待できる効果が大きいほど、ユーザー体験を向上することができ、施策が積み上がれば積み上がるほど、他のプロダクトとの差が生まれます。 これを徹底的に考えていくことが大切です。どこかの目線に偏らず、3つの観点を考え続けて Move Fast に優先順位を設定し続けます。 優先順位設定は施策案が出てきた瞬間に決められることが重要であり、そのためにはプロダクト設計、事業数値、ポエムで作ったコアバリューへの解像度の高さが重要です。解像度を上げるためには数値が必要で、実際に起きている事象を常日頃から把握することが大切です。 優先順位を設定したら突き進みましょう。そして再現性を作るために結果を振り返り、軌道修正できるところは再度優先順位を設定して修正しましょう。 楽しむ プロダクトを作っていると期待通りに改善されなかったり、ハプニングがあって計画が崩れてしまったり、意見がぶつかり合ったり、ウッ🤢となることも多々ありますが、楽しんでプロダクトを作ることが大切です。楽しめていないと作り続けることが難しいです。プロダクト作りは長距離走なので自分の感情と向き合って淡々とユーザー体験を良くしていきましょう。 自分が書いたポエムの世界観を信じていれば楽しく作り続けられます!  おわりに プロダクトマネージャーとしてプロダクトを作るときに重要だなと思っていることを書いてみました。3つしかなかったですが、ぼく自身全部完璧にできているわけではなく、日々トライ&エラーを繰り返しています。 Eコマースプラットフォーム「BASE」では、主なプロダクトとして、ネットショップ作成サービス「BASE」、ショッピングアプリ「BASE」の2つがありますが、まだプロダクトマネージャーがぼくしかおらず募集中ですので、ぜひ気軽にオフィスに遊びにきてください! binc.jp    
アバター
これは「BASE Advent Calendar」22日目の記事です。 devblog.thebase.in はじめに こんにちは。BASEでサーバサイドエンジニアをしている柳川( @gimupop )です。直近では、即時に資金調達ができる金融サービス「 YELL BANK(エールバンク) 」というプロダクトの開発を行っていました。 さて本日ですが、技術ブログなんですが技術の話はしません。私が部長を務める社内の部活がすごく良いという話をします。 BASEには、CLUB BASEという部活動制度があります。共通の趣味を持つ社員が部署を超えて集まり、なにかしらの活動をすることを会社から補助を出す形で支援しています。一例としましてはランニング部とかボルダリング部といった活動内容が想像できるものから、日本酒部といった一見何をするかわからないものまで、様々な部活があります。 本日はその中でも僕が部長を務めるボードゲーム部について紹介させていただきます。 ボードゲーム部とは さて、ボードゲーム部は何をする部活かといいますと、文字通りみんなでボードゲームをする部活です。活動内容がわかりやすい方の部活ですね。 基本的な活動としては、週に一回水曜日の業務後、会社の会議室でボードゲームをしています。 月に一回行われるBASEの締め会の日も活動していて、ここで普段ボードゲーム部に参加していない人と交流したりもしています。 また、他社のボードゲーム好きを会社に招いて開催したり、夏は湯河原で合宿も行いました。合宿では夕方から明け方までひたすらボードゲームをやってました。 合宿の様子 BASEのボードゲーム部には、生粋のボードゲーム好きから、普段あまりボードゲームをしない人たちまで様々な人がいます。要するに懐が深いです。 ボードゲーム部のここが良い 1.手軽 会社にボードゲームがあるので、思い立ったときにさっとできます。運動系の部活のように着替えなどを用意する必要がありません。 2.業務で関わりのない人と仲良くなれる これは部活全般に言えることなのですが、BASEの部活では基本的に複数部署から人を集めて活動することが推奨されています。そのため、普段業務で関わることのないあの人やその人と仲良くなることができます。 3.普通に話をしただけではわからないみんなの考え方がわかる 「業務で関わりのない人と仲良くなれるっていっても。何を話したら良いかわからないよ。」 そういう声もあると思います。でも安心してください。ボードゲームがそれを解決してくれます。 とりあえずそこにあるボードゲームをやりましょう。気の利いた会話はできなくてもボードゲームを通してお互いのことが理解できるはずです。 この人は割と素直にカードを出していくなとか、あの人は相手の動きをよく見てうまい手を打っているな、などなどその人の様々な側面を垣間見ることができます。 4.楽しい 何より大切なことですが、ボードゲームは楽しいです。 サイコロの目に一喜一憂したり、どちらのカードを出すか延々と考えてうまくいったり間違えたり。最初に描いてた戦略が潰されても諦めずに次の手を探して買ったり負けたり。全力で頭使ってみんなでなにかやる。そういったことが手軽にできるのがボードゲームの良いところかなと思います。 5.あらゆる場面でゲームをしっかり理解する能力を磨ける 弊社代表の鶴岡が先日の ブログ記事 で「王将を取ることが勝利」と言っていたように、今自分がどのようなゲームを戦っているのか理解することは重要です。 ボードゲームをプレイすることを通して、何をすれば勝利できるのかという本質をまず把握することと、そのためにいま何をすべきかを考えるくせが付きます。普段の業務に置き換えれば、どうすればプロジェクトが成功するのか、成功とはなにか、の定義がスムーズにできるようになるといったように仕事にも役立つのです。 ボードゲーム部を作りたくなったあなたへ おすすめボードゲームたち さて、ここまでボードゲーム部について語りましたが、皆さんボードゲームをやりたくなってきたのではないでしょうか? 「でも、ボードゲームっていってもたくさんあるから何を選んだら良いかわからないよ。」 そういった声もあると思います。でも安心してください。弊社ボードゲーム部が誇る膨大なライブラリーの中から、厳選したボードゲームを紹介させていだきます。 膨大なライブラリー。BASEでは部活動補助として毎月1万円補助が出るのでそれを購入費用に充てています。 ニムト プレイ人数:2~10人 概要 このゲームは弊社ボードゲーム部の大定番ゲームです。 10人まで参加でき、しかもルールが簡単なので、ボードゲームにあまり馴染みのない人でも楽しんでもらえると思います。大勢が集まる締め会や、合宿などでとても盛り上がるゲームです。 1から104まで数字が書かれたカードの中から10枚ずつをそれぞれが持ち、一定のルールで並べていき、6番目に並ぶカードを出してしまった人が失点してしまうというゲームになります。 特に人数が多いと、何を出せば失点をせずに済むかという部分に運が絡んでくるので、初めて参加する人でも楽しめると思います。 カードを一斉に出したあと、並べていく際には、 「まさかこのカードで失点するとは・・・。」 「ギリギリセーフ!」 といった阿鼻叫喚が聞こえてきてとても盛り上がります。 コードネーム プレイ人数:2~8人 概要 ボードゲームと言うと、計算が早かったり、論理的思考が得意な人が強いという先入観があるかもしれません。しかしこのゲームでは、チームでのコミュニケーションがとても大切です。そしてひらめきとそれを言葉で表現する力と、仲間が発した言葉を解釈する力が求められます。 簡単に説明すると、青チームと赤チームに別れて、並べられた25個の単語の中から複数ある自チームの単語を当てていくゲームです。リーダーが発する1つの単語から自チームの単語はどれかを当てていきます。1回のターンで複数の単語を当てていかなければ負けてしまうので、リーダーは複数の単語に共通するキーワードを連想するひらめき力とそれをチームメンバーが当てられるように表現する語彙力、単語チョイスセンスが求められ、メンバーはそれを解釈する力が重要になります。 言葉を発するリーダー側と当てるチーム側、お互いに相手のことを考えに考え抜いてゲームを進めていく必要があるので、自然と互いに親近感を持つと思います。 髑髏と薔薇 プレイ人数:3~6人 概要 「髑髏と薔薇」は、いわゆるブラフゲームになります。 ものすごく簡単に説明すると、手持ちのカードを順番に裏側にして重ね、重ねられたカードをめくっていき、薔薇ならセーフ、髑髏ならアウトです。相手の手持ちのカードや進捗を考慮し、他の人が髑髏をめくるようにうまく仕向けるのがコツです。 このゲームはいかに相手を欺くか、という駆け引きを楽しむゲームです。ルールがシンプルで短時間でできるのに、勝てるまで何度も遊んでしまうゲームの一つです。 あまりはまり込むと、誰も信じられなくなります。 パンデミック プレイ人数:2~4人 概要 一般的にはボードゲームは参加者同士で戦うものです。しかしパンデミックは違います。みんなで協力して世界を救うゲームです。 プレーヤーは協力して、世界中で蔓延するウィルスを撲滅するために行動していきます。 そ れぞれ特徴を持つ役職を持っていて、 「この能力をこういうふうに使えば、最小限のリスクで進められる。」 「ここはリスク取らないと間に合わないよ。」 などコミュニケーションとりながら進めていきます。 共通の目的に対して挑むので、達成できれば、みんなが嬉しいし、達成できなくても、次はこうしようといったような話ができて、参加者の考え方がわかるようになるゲームです。 まとめ 以上、BASEのボードゲーム部の紹介でした。 ボードゲームはやりたいけど部活作るのは大変そう、周りにやる人がいない、やり方とかよくわからないという方は、気軽にBASEに遊びに来てください! メッセ 待ってます! またボードゲーム購入の際は ショッピングアプリ「BASE」 をご利用いただけると嬉しいです! 明日はPMの神宮司です!お楽しみに!
アバター
こんにちは。BASEでサーバーサイドエンジニアをやっている、東口( @higasgt )です。 先日、「 PHPカンファレンス2018 」が開催されました。事前申し込みが2,000人超えというたいへん盛り上がったカンファレンスでした! 私は、当日セッション登壇したり、スポンサーとしてブース出展したり、運営スタッフをしたりして、大変楽しめたカンファレンスでした。 今日は、当日発表した内容やブースの様子について話したいと思います。 PHPカンファレンス2018 改めて、 PHP Conference 2018 とは、国内のPHPエンジニアが一斉に集まるテックカンファレンスです。 今年のテーマは「GROWTH」 今回、個人として公募で、25分セッション・LTの2枠で発表させていただき、BASEとしてもゴールドスポンサーとして協賛させていただきました。 発表内容 今回、25分セッション・LTの2つを採択いただいたので、2回壇上に上がることができました。 PHPバージョンアップと決済リプレイスを支えたユニットテスト 25分セッションにて発表した資料です。 ユニットテストについて次の2点をテーマにまとめた内容です。 テストがないコードにどうテストを書くか テストがないコードを生まないための考え方 私が入社してからの約1年間で起きたコードベースの変化と、それに対応して発生する課題と対策について、ユニットテストという観点でまとめさせていただきました。 セッション発表中 25分に無理やり凝縮して押し込んだ内容だったので、Q&Aの時間がとれなかったのですが、その後BASEのブースに来て質問していただいたりして大変ありがたい反響をいただけました。 発表駆動開発を一年間実践してきて今 LT大会にて発表した資料です。 私は、2017年10月にBASEに入社してから勉強会・イベントに参加できる時間が増えたこともあり、20本ほどLTやセッション発表をしてきました。 がっつり量をこなしてみた結果、「発表する」という行為自体が技術力向上にとても有益だと改めて感じています。 それを一言「発表駆動開発はええぞ!」の一テーマでまとめたものになります。 LT中 懇親会で、この発表フックで話しかけていただく機会が多く、「人見知りでも懇親会が楽しめる」という発表駆動開発のメリットを改めて時間しました。(話しかけていただいた方々本当にありがとうございます。。。) ブースの様子 BASEは、ゴールドスポンサーとして協賛しておりましたので、ブース出展もさせていただいていました。 ノベルティとして、ネットショップ作成サービス「BASE」をご利用いただいている 京都ぎょくろのごえん茶 さんのお茶を準備いたしました。 準備していたノベルティなどの配布物を配りきってしまうほど、たくさんのPHPerの方にお会いすることができ、大変楽しい時間となりました。 最後に 今回、少しだけカンファレンススタッフのお仕事も手伝わせていただきましたが、1年前から業務で忙しい中時間を割いて準備してくださっている方々がいるからこそ、PHPカンファレンスが開催できていることを改めて感じました。 運営委員会の皆様、本当にお疲れ様でした! また、2018年もそろそろ終わりですが、PHPerの年明けは早いことに、2019年1月26日に、「 PHPカンファレンス仙台2019 」が開催されますね。 こちらでは、「テストを書くのが辛くならないテスト駆動開発のアプローチ」というセッション発表・BASEとしてシルバースポンサーとしての協賛をします。 ぜひ、2019年1月26日、仙台でお会いしましょう!
アバター
この記事は、「 BASE Advent Calendar 2018 」の21日目の記事です。 devblog.thebase.in はじめまして。2018年2月にBASE株式会社へデザイナーとして入社した小山です。 技術ブログを書くのは初めてなのですが、今回は私が2月に入社してから今日までネットショップ作成サービス「BASE」で「Sketchを用いたデザインシステム」を作ってチームでのデザイン作業を効率化した話について書こうと思います。 入社当時の状況 私が入社した当時、デザインチームは人数が増え始めた時期で、大きな課題が2つありました。 デザインデータの管理 私が入社する前まではプロダクトに対してデザインデータを作るデザイナーが少なく、各デザイナーが個人のローカルでファイル管理をしていました。その為、誰がどの画面のデザインデータを持っていて、最新のデータがどれなのかを毎回メンバーに確認をして、最新のデータを送ってもらわないとデータを見ることができないという状況でした。 ファイル管理については、Abstractの導入でファイル管理とバージョン管理の問題を解決しました。この内容については12月7日の「 Abstractを用いたデザイン管理システムを導入して1年経ったお話 」で北村が詳しく書いているので興味のある方はぜひ読んでみてください。 デザインパーツの共通化 もう一つはデザインパーツがデザイン的にもデータ的にも共通化されていなかったことです。 当時のBASEは新旧のデザインが入り混じっており、どのパーツが最新のものでどのレイアウトに合わせて作っていいかが入社したての私には難しいものでした。また、コーディング用のスタイルガイドはあったものの、Sketch用のデータはなかった為、毎回パーツを作るかそのパーツを含むファイルを探してコピーしてくる必要がありました。 そこでSketchとAbstractのLibrary機能を使ってSketchを用いたデザインシステム(通称:BASE UI kit)を作る「UI コンポーネントプロジェクト」が立ち上がりました。 UI コンポーネントプロジェクト始動 BASE UI kit 作成にあたり、デザインチーム内の管理画面に関わるデザイナーとフロントエンドエンジニアでプロジェクトを2月末に立ち上げ、毎週定例ミーティングをしながら必要なデザインパーツの洗い出しを行いUI コンポーネントとしての仕様決めを行っています。 はじめに作ったBASE UI kit は1ファイルでPC、SPの全てのコンポーネントを管理しており、pageもグループごとに分けていました。 しかし、BASEの管理画面ではコンポーネントの数も多く、レイアウト側のデザインもファイル数が膨大になり、次第に管理が難しくなっていきました。 BASE UI kit 大改修 今まで1つのプロジェクトですべてのファイルを管理していましたが、BASE UI kit は専用プロジェクトに分離してAbstractのLink Library 機能を使って別のプロジェクトへリンクさせ、さらに1ファイルで管理していたコンポーネントはcommon、PC、SPの3ファイルで管理するように大改修しました。 また、BASE UI kit を大改修する一環として、コンポーネントの命名規則もAtomic Designのレベル分けでグルーピングして参照しやすいものに変更しました。(例:1 = Atoms、 2 = Molecules ) BASE UI kit を別プロジェクトにしたメリット BASE UI kit の編集をしたブランチをマージする度に他の各ブランチで変更をPullする必要がなくなった 右上に出てくる「Library Updates Available」をクリックするだけで最新のコンポーネントに更新できるようになった 個人の作業ブランチでBASE UI kitの編集ができなくなったことで、そのブランチがマージされるまで他のブランチで最新のコンポーネントが使えないという問題が起きなくなった(運用でカバー仕切れなかった問題が解決) ファイル分割したメリット コンポーネントを呼び出す時に階層を減らすことができた 1ファイル内のコンポーネント数が減ってコンポーネントを探すのが楽になった その他にもBASE UI kit以外のデザインデータもグループ分けをしてプロジェクトを分けて管理することで、担当外プロジェクトのAbstractのシンクを切ることができます。(これによりAbstractとSketchが軽くなったような気がします。※個人の感想です。) 大改修をする時の注意点 一度作成したBASE UI kitを別プロジェクトへ移行してファイルを分割する際に注意するべきことがいくつかありました。 BASE UI kitとして登録しているシンボルは一度ファイルから消してしまうと呼び出し先でリンクが切れる(つまりカット&ペーストした時点でそのシンボルはリンク切れになる) 既にライブラリ化済みのBASE UI kit(旧 BASE UI kit)を別ファイルの BASE UI kit(新 BASE UI kit)にリンクする場合、呼び出し先のデザインファイルでリンクが切れる前に新 BASE UI kit のコンポーネントへシンボルを置き換える作業が必要 大改修をする時に便利だったSketch プラグイン Symbol Organizer レイアウトされたシンボルを別ファイルのシンボルに一括で置き換えてくれるプラグインです。 同じ名前のシンボル同士を置き換えるのでシンボルの名前を変更するタイミングには注意してください。 Rename It コンポーネントの階層を整理したい時にシンボルの名前を一括変更できるのでとても便利なプラグインです。 今回はUI kitの階層も合わせて整理したのでとてもお世話になりました。 大改修の手順 Abstract上の全てのブランチをmasterへマージする Abstractで BASE UI kit 専用プロジェクトを作る 既にライブラリ化済みのBASE UI kit(旧 BASE UI kit) をBASE UI kit専用プロジェクトへコピーする BASE UI kit専用プロジェクトへコピーした新 BASE UI kitの中身を整理する(シンボル名は絶対変えない!) BASE UI kit専用プロジェクト以外のデザインプロジェクトに新 BASE UI kitを Link Libraryで紐づける デザインデータを開き、プラグインのSymbol Organizerを使って旧 BASE UI kit を新 BASE UI kitに置き換える(すべてのデザインデータで同じことをする) 新 BASE UI kitのシンボル名をプラグインのRename Itを使って整理する 現在、BASE UI kitの運用はこれで落ち着いています。 シンボル名の変更はシンボルを置き換える前とかでなければいつでもできるので、足りないコンポーネントが増えて階層を整理したくなったタイミングや、Atomic Design的にここじゃないよねって思ったタイミングで適宜修正しています。 まとめ UI コンポーネントをきちんと定義したことでデザイナー間やフロントエンドエンジニア間での仕様の認識を揃えることができ、また、BASE UI kitを作ったことで、シンボルを呼び出すだけで統一された UI コンポーネントを使うことができるのでデザイン作業が格段に早くなったと思います。 途中でUI kitの大改修もありましたが、毎日使うものだからこそストレスが少ないかたちで運用できる方が楽しく仕事ができるんじゃないかなと思います。(大変だったけどやってよかった!) 明日は ボドゲ部の部長 柳川です!
アバター
これは「 BASE Advent Calendar 2018 」の20日目の記事です。 devblog.thebase.in こんにちは。Data Strategy Group の岡です。趣味は珍しいお酒を飲むこと、将来の夢はウイスキーの蒸留所を持つことです。 私は機械学習エンジニアとしてまだ2年目なのですが、「この予測手法、本やweb上でほとんど見かけないな。」とずっと気になっている手法があります。ざっくり説明すると、時系列データをクラスタリングして同クラスタ内の平均を予測に使う、というもので、私より20くらい歳上の分析屋に教えてもらいました。下記の論文が一番これに近いと思います。 「 Time Series Forecasting through Clustering - A Case Study 」 今回は実験も兼ねてその予測手法を再現しようと思います。 使用データ そういえば、昨日は @Toshi_Day1 のFintechについての記事があり、先日の河越の 鶴岡さん観察日記 ではジャック・ドーシー氏の話題があったので、この流れで Twitterの株価 を予測してみましょう。 ナスダック のサイトから5年分の日次株価データをダウンロードしました。 ここから直近30日分を検証データとして切り出し、それ以前のデータを学習データとして使います。 #!/usr/bin/env python3 # モジュール import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error from matplotlib import pylab as plt # 読み込み & 日付でソート twtr_stock = pd.read_csv( 'twtr_stock.csv' ).sort_values( 'date' ).reset_index(drop= True ) # 末尾30件を検証データとして分割 train_df = twtr_stock[ 0 :- 30 ].reset_index(drop= True ) test_df = twtr_stock[- 30 :].reset_index(drop= True ) 先頭数件は下記のようになっています。 この中で close(終値) の値を予測していきます。 下のグラフはcloseの値を時系列でプロットした結果です。 plt.plot(twtr_stock[ 'close' ]) 前半大きく下り傾向があり、後半から徐々に上がり調子になっていますね。このデータから後に続く30日分のデータを予測することが今回の目標です。 予測の手順 この予測手法を直感的に説明してしまうと、 1. 時系列データを等間隔でスライドさせながらカーブを切り出して 2. それらを形状の似ているもの同士でグルーピングし 3. 同じグループ内で末尾の株価だけ取り出し、その平均を予測値として扱う という流れになります。もう少し詳しく説明すると 時系列データから幅(N + K)のスライド窓の作成 スライド窓ごとに平均0、分散1に標準化 スライド窓の手前N個を PCA + k-means でクラスタリング 同クラスタ内で、N+K時点のデータの平均値を計算 cos類似度で近傍クラスタを求め、そのクラスタの平均値を予測に使う という手順になります。 1. 時系列データからスライド窓の作成 スライド窓とは、時系列データから一定の幅で1時点ずつスライドさせながら取り出して作るカーブのことです。下図がそのイメージになります。 スライド窓、だとわかりにくいので今後はカーブと呼んでしまいます。 ここで作られる複数のカーブを似ているもの同士でまとめ、末尾の値の平均で予測を行います。 今回は直近20日のデータから5日先のデータを予測するとします。(20 + 5)日分のデータで切り出したいので、幅25で1日ごとにスライドさせたデータセットを作成します。 TRAIN_SIZE = 20 TARGET_FUTURE = 5 WINDOW_SIZE = TRAIN_SIZE + TARGET_FUTURE def split_window_data (array, window_size): length = array.shape[ 0 ] roop_num = length - window_size + 1 window_data = np.stack([ np.hstack( np.array(array[i: i+window_size].astype( 'float64' )).reshape(window_size, 1 ) ) for i in range (roop_num) ]) return window_data train_close = np.array(train_df[ 'close' ]) window_data = split_window_data(train_close, WINDOW_SIZE) 2. カーブごとに標準化 カーブごとに切り出したデータは、あるものは(20 30 35 25 30)、別のものは(60 80 70 80 100)だったりとスケールが異なります。この生の値でクラスタリングを行うと、スケールの大きいもの同士でまとまってしまいますが、今回は時系列の形状や特徴が似ているもの同士でまとめる必要があります。 そのためカーブごとに「標準化」という操作を行い、平均0、分散1のスケールを統一してしまいます。 # 標準化 sc = StandardScaler() window_sc = np.stack([ np.hstack(sc.fit_transform(vec.reshape(WINDOW_SIZE, 1 ))) for vec in window_data ]) 標準化については下記が参考になります。 「 統計における標準化の意味と目的 」 3. PCA + k-means でクラスタリング ここからの手順を下図を使って説明します。同じ幅のカーブを冒頭で作成しましたが、今度はこれらを形の似ているもの同士でまとめていきます。 k-meansとはクラスタリングの一つで、数学的に似ている(数学的に距離が近い、と言ったりします)データを任意のグループに分類します。分類後のグループを「クラスタ」、各クラスタの重心に位置するデータを「代表ベクトル」と呼びます。代表ベクトルも後の計算で使うため、ここで算出しておきます。クラスタリングの後、分類時には外していた末尾のデータの平均値を計算します。末尾というのは、今回でいうと25日分のカーブのうち末尾5日分のデータのことです。 細かい話になるので上図には記載しなかったのですが、今回の予測ではPCAという処理を通してからk-meansを実行します。なぜPCAが必要か、については記事末尾の補足にて記載しております。 クラスタリングの実行 それでは、PCA + k-means クラスタリングを行い、クラスタごとの平均値を計算していきます。 def curve_clustering (array, curve_len): train = np.stack([vec[ 0 :curve_len] for vec in array]) test = np.stack([vec[curve_len:] for vec in array]) test_len = test.shape[ 1 ] # PCA pca = PCA(n_components=curve_len) pca.fit(train) # 共分散行列から写像 cov_mtrx = pca.get_covariance() train_pca = np.dot(train, cov_mtrx) # あとで元に戻すため、共分散行列の逆行列を求めておく cov_mtrx_inverse = np.linalg.inv(cov_mtrx) # k-meansクラスタリング curve_clst_size = int (np.sqrt(train_pca.shape[ 0 ]/ 2 )) cls = KMeans(n_clusters=curve_clst_size, random_state= 123 ) curve_clst = cls.fit_predict(train_pca) # クラスタ毎に、カーブのリスト、平均、分散、代表ベクトルを求めておく curve_df = pd.DataFrame({ 'curve_clst' : curve_clst , 'train' : [vec for vec in train] , 'train_pca' : [vec for vec in train_pca] }) for i in range (test_len): curve_df[ 'test{}' . format (i)] = [vec[i] for vec in test] print ([col for col in curve_df.columns if 'test' in col]) curve_clst_dict = { cluster : { 'test_means' : [df[col].mean() for col in df.columns if 'test' in col] , 'test_medians' : [df[col].median() for col in df.columns if 'test' in col] , 'test_stds' : [df[col].std() for col in df.columns if 'test' in col] , 'train_cluster_center' : np.dot(cls.cluster_centers_[cluster].flatten(), cov_mtrx_inverse) , 'train_pca_cluster_center' : cls.cluster_centers_[cluster].flatten() , 'train_vectors' : [vec for vec in df[ 'train' ]] , 'train_pca_vectors' : [vec for vec in df[ 'train_pca' ]] } for cluster, df in curve_df.groupby( 'curve_clst' ) } return (curve_clst_dict, cls, pca) curve_clst_dict, cls, pca = curve_clustering(window_sc, TRAIN_SIZE) ここではクラスタ数を curve_clst_size = int (np.sqrt(train_pca.shape[ 0 ]/ 2 )) と決めていますが、理由は記事末尾の補足に少しだけ記載しております。 クラスタリングの結果の可視化 それらしい分類になっているか、クラスタ毎のカーブをまとめてプロットしていきます。 # グラフを行列形式で表示する clst_size = len (curve_clst_dict) row_size = int (clst_size/ 3 ) if clst_size% 3 == 0 else int (clst_size/ 3 ) + 1 x_axis = [x for x in range (WINDOW_SIZE - 1 )] fig = plt.figure(figsize=( 19 , 30 )) for key in curve_clst_dict: # カーブのリストを取り出す clst_info = curve_clst_dict[key] raw_curves = clst_info[ 'train_vectors' ] # subplotと行列番号の設定 row_n = int (key/ 3 ) col_n = key% 3 ax = plt.subplot2grid((row_size, 3 ), (row_n, col_n)) # カーブのプロット for raw_curve in raw_curves: ax.plot(raw_curve, color= 'steelblue' , alpha= 0.3 ) # 区間のプロット upper_95 = np.hstack([np.repeat(np.nan, TRAIN_SIZE- 1 ), np.array(clst_info[ 'test_means' ]) + 2 *np.array(clst_info[ 'test_stds' ])]) lower_95 = np.hstack([np.repeat(np.nan, TRAIN_SIZE- 1 ), np.array(clst_info[ 'test_means' ]) - 2 *np.array(clst_info[ 'test_stds' ])]) ax.fill_between(x_axis, upper_95, lower_95, facecolor= 'gray' , alpha= 0.4 ) # 平均値のプロット ax.plot( list (np.repeat(np.nan, TRAIN_SIZE- 1 )) + list (clst_info[ 'test_means' ]), color= 'coral' ) ax.set_title( 'curve cluster{}' . format (key)) plt.show() 実行結果は下記となります。 (本当はクラスタ23まであるのですが、長い上に結論も変わらないのでクラスタ8まで載せています。) 青色の線がカーブの集まりです。一つのクラスタを注視すると、変動の大きいカーブと小さいカーブが混在しつつも、大まかなトレンドは同一であると分かります。 オレンジの線がクラスタリングに使わなかったデータの平均値です。グレーは (平均 ± 2 * 標準偏差)の範囲を表しています。やや分散の大きいクラスタが多い印象です。 4. cos類似度で近傍クラスタを求める ここからの手順を下図を使って説明します。今度は、未知データがどのクラスタに近いかをcos類似度を用いて探します。 cos類似度とは、2つのベクトル(ここではカーブのこと)の類似度を測る指標です。上の図中では未知データのカーブと、各クラスタの代表ベクトル(青色の点線)を比較し類似度を計算しています。クラスタ1との類似度が高いと判定され、未知データのカーブの先に、クラスタ1の平均値(オレンジの点線)を当てはめて予測値としています。 それでは実際のデータで実行していきます。 最近傍のクラスタを見つける 下記のコードでは、2018年11月以前のデータを再びスライド窓に分割し、標準化しています。各クラスタの代表ベクトルとの類似度を求めるため、切り出す幅が TRAIN_SIZE になっている点が冒頭と異なります。 # TRAIN_SIZEで分割 window_data_train = split_window_data(train_close, TRAIN_SIZE) # 標準化 sc = StandardScaler() window_sc_train = sc.fit_transform(window_data_train.T).T 次に切り出したカーブのベクトルと、各クラスタの代表ベクトルの類似度を計算し、もっとも類似度が高いクラスタの番号を返す関数を作ります。 # cos類似度を計算する関数 def cos_sim (v1, v2): return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)) # もっとも類似度の高いクラスタの番号を返す関数 def calculate_neighbor_clst (window_vec, curve_dict): cos_sim_vec = np.array([ cos_sim(window_vec, curve_clst_dict[clst][ 'train_cluster_center' ]) for clst in curve_clst_dict ]) return cos_sim_vec.argmax() 最近傍クラスタから平均値の取り出し 続いて、最近傍クラスタの平均値を取り出します。取り出したらスケールを戻して予測値とします。 # もっとも近いクラスタの平均値を取り出す scaled_means = [] for vec in window_sc_train: neighbor_clst = calculate_neighbor_clst(vec, curve_clst_dict) scaled_mean = np.array(curve_clst_dict[neighbor_clst][ 'test_means' ][TARGET_FUTURE - 1 ]) scaled_means.append(scaled_mean) # 取り出した平均値を元のスケールに戻す scaled_means = np.array(scaled_means) pred_means = sc.inverse_transform(scaled_means) 以上で予測値を算出するところまでは完了です。次の節で予測がどれくらい当たってたのかを検証していきます。 5. 予測結果の評価 予測結果と実際の値をプロットしてみましょう。 act = train_close[WINDOW_SIZE:] pred = pred_means[ 0 :-TARGET_FUTURE- 1 ].flatten().tolist() plt.plot(act, label= 'act' ) plt.plot(pred, label= 'pred' ) plt.legend() 青色が実測値、オレンジが予測値です。すごく当たっているように見えますが、実は数日前のラグを取ったような予測になっています。これでは予測できたと言えません。 株価の「上昇する」か「下落する」かの予測 今回は直近20日のデータから5日先のデータを予測する、というテーマだったので、20日目の株価から5日先の株価が上がっているか、下がっているかの判定をしてみましょう。 # 20日目の株価と5日後の実際の株価を比べ、上がってるor下がってるか act_updown = [ train_close[i + WINDOW_SIZE] > train_close[i + TRAIN_SIZE] for i in range ( len (train_close) - WINDOW_SIZE) ] # 20日目の株価と5日後の予測株価を比べ、上がってるor下がってるか pred_updown = [ pred[i] > train_close[i + TARGET_FUTURE] for i in range ( len (train_close) - WINDOW_SIZE) ] 最初の act_updown には20日目と比較して5日後の実際の株価が上がったか、下がったかの真偽値を格納しています。次の pred_updown には5日後の予測の株価と比較した結果が入っています。この予想結果の正答率を計算していきます。 TF = (np.array(act_updown) == np.array(pred_updown)) sum (TF)/ len (TF) 結果は 51.8% でした!シンプルに株価の上下を予想してもほとんど当たってないですね笑 検証データと予測値の比較 今度は冒頭のほうで検証用に残していた、2018年11月以降の30日分の株価を予測してみましょう。 30日分の予測なので、ひとつずつ予測値をカーブに追加していきながら、最終的には20個の予測値を使って30日先の株価を予測することになります。 # スライド窓から予測値を算出する関数 def predict_ (window_vec, target_future): test_sc = StandardScaler() vec_sc = test_sc.fit_transform(window_vec.reshape(TRAIN_SIZE, 1 )).T neighbor_clst = calculate_neighbor_clst(vec_sc, curve_clst_dict) scaled_mean = np.array(curve_clst_dict[neighbor_clst][ 'test_means' ][target_future]).reshape(- 1 , 1 ) return test_sc.inverse_transform(scaled_mean.reshape(- 1 , 1 )) # 予測値を追加しながら、次点の値を予測 def predict_forward (window_vec, n_forward, target_future): predictions = [] vec_len = window_vec.shape[ 0 ] train_vec = window_vec.copy() for _ in range (n_forward): pred = predict_(train_vec, target_future).flatten() predictions.append(pred[ 0 ]) train_vec = np.append(train_vec[-vec_len + 1 :], pred) return predictions # テストデータの長さ分の予測値を算出 test_len = len (test_df) last_window = window_data_train[- 1 ] predictions = predict_forward(last_window, test_len, TARGET_FUTURE- 1 ) この予測を重ねた結果と、30日分の実測値をプロットした結果が下記となります。 plt.plot(test_df[ 'close' ], label= 'act' ) plt.plot(predictions, label= 'pred' ) plt.legend() 青色が実測値、オレンジの線が予測値です。実測値より予測値はなだらかな線になっています。やはり予測値を平均で代用しているので、変動の大きい時系列を捉えるのは不得意そうですね。 まとめ 株価を使う時点で予想してはいましたが、さっぱりうまくいきませんでした。この手法を教えてくれた人は「これで為替レートの予測がうまくいった!」と言っていたので、万に一つの可能性があって株の予想ができたら、、、と思いましたが現実は厳しいですね。 これの使いどころとしては、クラスタ毎にまとめた平均値、つまりノイズを省いたトレンドを検出できるので、下記のケースなら有効かもしれません。 局面変化の検知 長期ではなく短期の予測 件数の少ない時系列データに対し、傾向の似ている別の時系列データから予測値を算出 以上が、私の記憶と数少ない資料を頼りに再現した予想手法でした。これを読まれたどなたかが、「その分析知ってるけど使い方違うよ!」などご指摘くだされば何よりです。 明日はデザイナーの小山さんです!お楽しみに! 補足 PCAとk-meansの組み合わせ PCAとk-meansを組み合わせることでより綺麗にクラスタリングできるという、イケてる分析屋の間ではよく使われるテクニックだそうです。 私は最近まで知りませんでした。 PCAとk-meansの関係については、下記の資料が参考になるかと思います。 「 K-means Clustering via Principal Component Analysis 」 クラスタ数について 下記はk-meansを実行する部分のコードです。 def curve_clustering (array, curve_len): ~~~ # k-meansクラスタリング curve_clst_size = int (np.sqrt(train_pca.shape[ 0 ]/ 2 )) ~~~ ここでしれっとクラスタ数を (サンプルサイズ/2)の平方根で設定していますが、適切なクラスタ数が不明なときはこれで良かろう、という先人の知恵なんだそうです。以下のやりとりから文献にたどり着いたので、これから理解を深めていこうと思います。 「 How can we choose a "good" K for K-means clustering? 」
アバター
この記事は「BASE Advent Calendar 2018」19日目の記事です。 devblog.thebase.in はじめに こんにちは。BASEの100%子会社であるBASE BANKの矢部( @Toshi_Day1 )です。BASEの金融事業という立ち位置で先日リリースした、リスクなく即時に資金調達ができる金融サービス「 YELL BANK(エールバンク) 」を中心に複数の金融事業を立ち上げ責任者をしています。 今回、社をあげてのアドベントカレンダーということで、テックな内容ではありませんがFinTechについて少し書き連ねていきたいと思います。 ここ1年弱、消費者と事業者の混ざり合ったようなユーザー層への金融サービスに思いをめぐらせつつ、決済をコアとした事業構造のBASEに身を置き、またFinTech企業や金融機関の方々とお話させていただく中で学んできたことをもとに、来年のファイナンス領域におけるFinTechトレンドを予想したいと思います。 より多くの人にとって金融サービスが普遍的なものになり、個々人が想像力や可能性を広げることができる世の中を作るため、日々事業に向き合っています。このブログ記事を読んで、興味が湧いた方がいらっしゃれば、ぜひ気軽にご連絡ください。ディスカッションやブレストなども誘っていただければ嬉しいです。 ※Crypto、Blockchain、STOなどと、面白いと感じることも多いのですが、まだ勉強中のため割愛します。 ※この記事の内容はあくまで個人的な意見・見解を示したものです。 1. 個人やスモールビジネスが持つ資産を流動化し、換金性をあげるサービスが登場 個人の資産流動化の流れ 資産の現金化という意味では2017年の「CASH」を筆頭に、それまで行われていた「メルカリ」で物を売って現金に変える、という行為を簡略化するような形で即現金化サービスがでてきました。また2018年には給与の前払いサービスなどへ多くの事業者が参入していきました。このような消費者向けの少額資金ニーズが顕在化したことについては、個人的には仮想通貨の価格高騰により我々が認知する割引現在価値が大きく変化したからであると、こちらの note で考えてみたこともあります。 これらのビジネスに共通しているのは、個人のBSを想定したときに流動資産科目をキャッシュに変えるような機能であることと言えます。基本的には、引き続き2019年もこのトレンドが続いていくと考えていて、ブランド品や(パート・アルバイトを含めた)給与以外にも身の回りにある高単価な物品、あるいは無形材をバーティカルにカテゴリー化して換金できるような仕組みに挑戦する企業が出てくるのではないのでしょうか。タイミングはもう少し先だと思いますが、権利や契約関係、データなどのBSに反映されにくいものもブロックチェーン上で資産管理され、換金性が高まるような変化が起こるでしょう。 オンラインファクタリングサービスの登場 一方で、類似の仕組みを事業者に当てはめたサービスが2018年の下半期からぽつぽつとリリースされ始めています。もっとも多かったケースとしては、事業者が保有する売掛債権を譲渡することで資金調達をする"ファクタリング"のビジネスをオンライン化していくケースです。 直近の事例としては、下記が挙げられます。 クラウドワークスが提供する「フィークル(feecle)」 GMOクリエイターズネットワークが提供する「FREENANCE(フリーナンス)」 マネーフォワード100%子会社であるMF KESSAIが提供する「MF Kessai」 三菱東京UFJグループ運営のMUFJ Digital Accelerator出身のOLTAが提供する「OLTA(オルタ)」 また「YELL BANK」もスキームとしてはファクタリングを応用させたものになっています。 フリーランスや中小企業に特化しつつ、各社自社サービスの強みを生かす形での参入パターンと、全くの新規での参入との両パターンが存在していますが、ファクタリングは産業としての歴史は比較的浅いこともあり、ほとんど認知されていません。おそらく経営者や財務関係の方でもファクタリングについての知見を持ち合わせている方はごく少数なのではないでしょうか。 アメリカでは既に「Fundbox」や「BlueVine」など売掛債権を活用したファクタリングやABL(動産担保融資)等のファイナンススキームでユニコーンとなる企業も登場し始めています。今後日本のマーケットにおいてもFinTechスタートアップによって、本格的にファクタリングが流行っていくのか、とても楽しみです。 流動資産を活用したファイナンス 売掛債権を活用するファクタリングのように、流動資産(不動産に対して動産という)を活用したファイナンススキームは、ファクタリングやABLなど、アメリカでの市場形成を参考に日本では2000年代から中小企業庁を中心に推進しようとする動きが活発でした。しかし、残念ながら未だに一般的に利用されているとは言い難い現状があります。 中小企業のバランスシートをみると、動産の資産価値ベースで売掛債権で87兆、棚卸資産46兆、その他流動資産47兆円が積み上がっています。借り入れを見てみると金融機関、その他から合わせて約240兆円あり、この規模が事業性ファイナンスにおけるTAMという考えることも可能かと思います。加えて小規模事業者のマーケット、フリーランスなど統計上捉えられない市場も加味すると、マーケットのポテンシャルの凄さに気付くかと思います。細かいセグメントでの分析は別の機会にしようと思いますが、チャレンジに値するマーケットが存在することは明らかです。 (中小企業白書 第2部 中小企業の稼ぐ力「 第5章:中小企業の成長を支える金融 」より) 事業者向けのFinTechサービスとしては、貸金業との対比における参入障壁の低さからファクタリングが先行していきますが、商流ファイナンスの流れに乗っかって在庫、POなど、売掛債権よりも更にサプライチェーンを遡った部分でのファイナンス手法を提供するインターネット企業が後々生まれてくるでしょう。一例としては、事業者の物流管理がクラウドサービスで行われるようになった際に、生産過程での商材を担保に運転資金融資をするなど、ある意味で商社金融によって担われていたようなサービスを、個人やスモールビジネスでも受けられるような時代がくるでしょう。 (日本銀行金融高度化センター ITを活用した金融の高度化に関するワークショップ「データを活用した金融の高度化」) 競争環境は厳しめ このように事業者の資金調達課題、特に運転資金の課題に対しての切り口は現時点でも複数考えることができます。また、既存の市場環境をみてみると無数の中堅、小規模な事業者が激しく戦っている状態で、まだ誰が勝ち切っているとは言い難いのが現状です。 更に言うと、トランザクションレンディングの切り口でAPI型、マーケットプレイス型、会計型、決済型、それぞれの参入が続いていく中で、ファクタリングや商流ファイナンス単体でどこまでスケーラビリティをとれるかは難しいところかもしれません。 新規参入の際に既存プレイヤーとの差別化として、外部サービスとのAPI連携や銀行口座情報の取得など、多くのデータポイントを作り出していくことを戦術的に取りれる事例が増えていきますが、マーケットのマジョリティーを占めるであろう中小製造業社や卸売業者がデータソースとなるようなクラウドサービスを導入しているかといえば、現状まだまだな状況です。 米国事例との単純比較で言えば、独立的にファイナンスサービスを提供するテクノロジー企業(代表的な例で言えば「Kabbage」)の立ち上がりが、決済やマーケットプレイス企業である「PayPal」、「eBay」と同時期であったことにより、複数のユニコーン企業を産む結果に繋がっている一方で、日本ではマーケットプレイスが先行したために融資・ファクタリングのテックプレイヤーが急拡大する余地が薄くなってしまっています。 このような市場環境での新規参入に取りうる事業戦略は、他産業の事例や金融業界の歴史を振り返ると6つほどに類型できると私自身整理していますが、これについてはまた別の機会に書いてみたいと思います。 何にしても事業性融資/中小企業の資金調達という巨大マーケットで戦うプレイヤーが増えることは、資金需要者からするとファイナンスオプションの増加につながり、メリットは計り知れません。 CACの問題や、ファクタリングなどの参入障壁の低さ、債権回収のパワー関係、資本政策の難しさなど、あげようと思えばいくらでもこの市場でビジネスを生み出していく上での壁を思いつくことができます。しかし、我々はスタートアップとして課題があれば解決していかなければいけない立場にあります。BASEもBASE BANKを通してこの市場に参入しているわけなので、新規サービス、産業の発展、そして顧客の課題解決に知恵を働かせていきたいものです。 2. 既存のSaaSサービスから派生した金融サービスへの展開 クラウド会計サービスの貸金業進出は言わずもがなとして、ピンポイントなところで言うと、SmartHRが金融サービスを展開していくでしょう。代表の宮田さんご本人の ブログ にも、 おそらく FinTechっぽい事業になる予定です とありますし、確度は高いのではないでしょうか。 事業展開としては、給与前払い系、あるいは会社が従業員へ貸付する場合は貸金業登録を必要としないので、従業員への貸付や債権管理をサポートする機能、給与から天引き回収などの事業展開かなと思っています。自社で「SmartHR Pay」のような機能を用意して、給与振込自体を自社サービス内に留める、といったことも妄想はできますが、現在のPayment市場では難しいのではないでしょうか。そうすると選択肢としては、やはり貸付周りや、積立や資産運用サービスを「Folio」など他社とのアライアンスで提供していくような新規事業を作っていくのではないかと考えます。 決済+ECで事業を作りあげてきたBASEは、個人的にはSquareと重なって見えることが多いのですが、彼らがPayroll領域へとプロダクトの幅を広げていることもありSmartHRとも若干被り始めているように映り、とても興味深いところです。 日本ではまだSaaS自体が立ち上がっているフェーズということもあり、金融サービスへと展開していくケースは少ないかもしれませんが、産業ごとのバーティカルSaaSの特性を生かして個々の金融課題を解決していく様子は想像するだけでワクワクするものです。 物流や医療機関など、各カテゴリーごとに立ち上がったSaaSがホワイトラベル化する銀行とアライアンスを組みながら金融事業を展開していく、というストーリーは多くの方が想像するところだと思いますし、これが実現される世の中であってほしいです。 3. 株式投資型クラウドファンディングの立ち上がりの兆し 事業としてエクイティクラウドファンディングが立ち上がりはじめたのは2012年頃に米国でJOBS Actが成立してからだと記憶していますが、欧米に引き続き日本でもようやく参入の兆しがみえはじめています。 (参考記事: JOBS ACTによる米国証券法等の改正 ) またスタートアップ界隈でもエンジェル投資が一般化され始めており、この流れに乗っかりたい投資家は潜在的に多いのではないかと考えています。かくいう私も個人的な趣向としてFinTechスタートアップを中心に、人間の可能性や想像力を拡大していくような企業へ50〜300万ほどの少額投資したいと思うことが多々あります。(ほとんど自己研鑽/事業立ち上げが好きだからという理由ですが。) もちろん調達側の企業とのマッチングが本質であるので、一般化されるのは難しいかもしれません。しかしながら特定のビジネスレイヤーに対しての拡大は非常に早いのではないかと、半分願望ですが考えています。 4. 比較レイヤーの新規参入 顧客へダイレクトにサービス提供する事業者が増えるにともなって、インターネットのことわり通り、顧客側には比較検討するニーズが発生します。しかし、融資領域では商品特性がコモディティ化されており、金融機関ごとに差別化することが難しい現状があります。ここに一歩踏み込んだ形で比較サービスを展開するプレイヤーが出てくるでしょう。 例えば融資領域ですと、現状検索結果はアフィリエイトサイトで溢れています。一方で融資の媒介(送客・広告ではなく、融資契約を仲介すること)は、貸金業法で登録済みの事業者しかできないことになっており、気軽には参入することができません。 新規の比較レイヤーは正式に貸金業登録を完了させた上で、自社サービス上で財務分析・信用調査・金融機関による審査と条件交渉などを複数同時平行で進めることができるようなプラットフォームを目指して生まれてくると思います。このように既存金融機関が融資プロセスの中でコストをかけて行なっていた一部の過程をアウトソースするという切り口での参入は、他産業ではよく見かける事例でもありますが、金融はブラックボックス化されやすい特性からか未だスタートアップが入り込めていません。 米国事例で言えば、「 Fundera 」がこれに近いかもしれません。 Crunchbase を見ると2015年のシリーズB以降の資金調達がないですが、金融機関の広告、オペレーションコストを考えるとマーケットは十分と言えそうです。 5. 金融リスク管理系SaaSサービスの発展 比較レイヤーの論理と同じで、プレイヤーが増えればその分事業者の課題の総量も増えていきます。 特に新規参入のスタートアップにとって、与信、債権管理、回収、ALMマネジメント、信用リスクモデルの構築、ポートフォリオ管理、統合的リスク管理、担保や保証などの各種経営管理要件を自前で準備して運用していくことは大きな負担であり、そもそも人材マーケットにこれらの経験がある人はほとんどいません。 金融におけるリスクは信用リスク、オペレーショナルリスク、市場リスクなどに分けて考えられますが、まずは信用リスクの部分を補完するサービスを展開していく事業者がでてくるかと思います。そもそも金融におけるリスク、というのは情報の非対称性と不確実性の両性質を持っています。前者についてはインターネット的な解決手段を提示しやすく、後者については機械学習を筆頭にAIがコアバリューとなったソリューション提供が増えていくでしょう。 先行する米国では、すでにいくつかのサービスが立ち上がっています。債権管理であれば「 Yaypay 」、債権回収領域の「 TrueAccord 」、Banking as a Serviceの「 Plaid 」などがこれにあたります。 また信用調査に関して言うと、日本では伝統的な企業信用情報サービスはTDB(帝国データバンク)やTSR(東京商工リサーチ)による独占状態です。この領域は市場規模も1000億以上あり、かつ課題が多く、上記のような切り口でのスタートアップによる参入もあるはずです。シードステージのスタートアップでは「 アラームボックス 」などが存在していますが、まだまだ参入企業数が少ない印象です。2019年は盛り上がりを見せることを期待しています。 おしまい 注目しているスタートアップや各市場への参入の戦略など、他にも考察したいことは多いのですが、今回のブログでは一旦ここまでとします。色々と考えを書き連ねてきましたが、まとめたり分析したり考えを書くだけならば、私個人としてはノーバリューだと思っています。 私はアナリストでもコンサルタントでもなく、あくまでも起業家/事業家としてしっかりと新しい時代の金融サービスを創り上げ、より良い未来に貢献いきたいと思います。 Be Hopeful!! お茶・ランチも常時募集してますので、こちらの リンク や Twitter からでも気軽にご連絡ください! 明日はBASE BANKチームを機械学習エンジニアとして支えてくれている岡さんです!
アバター
BASE Advent Calendar 2018 18日目 「 BASE Advent Calendar 2018 」の18日目の記事です。 devblog.thebase.in お久しぶりです。BASEビール部部長(& Data Strategy Group)の氏原です。 アドベントカレンダーの季節が来て今年も終わりかと実感しているところです。 年末年始、どこにビール飲みに行くか今から悩んでます。 参考: 大晦日もお正月もクラフトビール! 年末年始営業日カレンダー (2018 – 2019) – クラフトビールのお店の予定がわかる さて、今回はアドベントカレンダーということで機械学習そのもののお話は他のData Strategy Groupのメンバーが書いてくれるでしょうから、 私はちょっとインフラ寄りのお話をさせていただこうかと思います。 以前 類似商品APIのお話 を書きましたが、 それ以降もData Strategy Groupでは関連ワードAPIとか売上予測APIとかいろんなAPIを作ってきました。 APIはAWS API Gatewayを利用してBASE本体に提供していますが、ある日AWSさんからAPIの構成について貴重なアドバイスをいただきました。 どういう内容でご指摘いただいたか、そしてそれにどう対応したか、対応して良かったことを書こうと思います。 Data Strategy GroupのAWSのインフラ構成 Data Strategy Groupは自分たち専用のAWSアカウントを持っていまして、その内部構成は自由に決められます。 メンバーが各々で開発を好きに進められるように機能ごとにVPCを分けて、自分が担当しているVPC内については好きに作っていいよという構成にしました。 AWS環境のVPC構成 VPC間で通信が必要な場合はVPC Peeringで繋ぎます。 VPC Peering こうして各機能を疎結合にして、各メンバーが割と好きに開発を進められるようにしてありました。 そして問題のAPI Gatewayですが、これは各VPCから生やすようにしていました。 API Gateway API Gateway自体はVPCとは繋がっていませんので、API Gatewayに来たリクエストをVPC内のサーバにルーティングするにはVPC Linkを設定する必要がありました。 エラー ある日新しく作ったVPCにAPI Gatewayを生やすためにVPC Linkを作成しようとするとエラーが起こりました。 どうやらAWSの制限に引っかかったようです。 1アカウント、1リージョンあたりのVPC Linkの数は初期状態では5つに制限されています。 VPC Linkの制限 まだ慌てるような時間ではありません。AWSはそもそも初期状態では結構厳し目に制限かかってますからね。 ちゃんと使い出したらすぐに制限に引っかかって緩和申請出すというのはAWS使ってる方なら経験があるでしょう。 引き上げ可能かに「はい」と書かれているわけですからいつも通り制限緩和を申請しましょう。 どれだよぅ そのままドンピシャな選択肢が見つかりません。 制限タイプの「API Gateway」とか「API Gateway管理」とか「VPC」とかの中を探したんですが見つかりません。 だんだん嫌な予感がしてきました。 仕方ないので技術サポートに問い合わせました。 結果、 「VPC Linkの項目はない。適当な項目選んで申請理由の説明のところにVPC Link数増やして欲しい旨記述してほしい」 とのこと。 …今まで誰も申請してないんだろうか。 気を取り直してそれで申請しました。その結果がまさかのNG。 「VPC Linkの数は増やすことをあまり想定していない。利用方法について聞かせて欲しい。」 インフラ構成変更 その後AWSの担当の方とのミーティングなどを経て、VPC Linkの数を増やすことは諦めて構成を変更することにしました。 API VPC爆誕 まずAPI提供用のVPCを一つ用意してAPI GatewayとVPC Linkで繋ぎました。 VPC Linkの一方の端はNLBです。で、このNLBから直接各VPCのALBに繋ぎたかったんですが、NLBにそういった設定はできません。なので一旦HAProxyにリクエストを飛ばして、ここで各VPCのALBへ振り分けるようにしました。各VPCのALBはVPC内のマイクロサービスへリクエストをルーティングします。 このような構成にすることでVPC Linkの数は1つあればよいようになりました。 さて、こうしてみると実はこの構成のほうが良かったんじゃないかと思います。 その理由としては キャッシュをAPI VPC内でやるようにすれば各機能でキャッシュとか考えなくてもAPI VPCで統一的に扱える。 APIの入れ替え、A/Bテスト、障害時の対応などがHAProxyの設定変更で行える。 複数の機能を統合したAPIの提供をAPI VPC経由で行える。例えば画像系とテキスト系の類似度を両方使った類似商品APIなど。 APIを外部に提供するときに考えなくてはいけないことと、提供する機能を綺麗に分離することができたように思います。 まとめ 実運用されていてかつ試行錯誤させてくれる環境って貴重ですよね。いろんな知見が溜まっていく。実は上で説明した今の構成もさらに改善中で来年頭くらいにはまたちょっと変わっちゃってると思います。Data Strategy Groupの環境はまだまだ手探りで構築中ですが、それがまた楽しいでところでもあります。 ではこのへんで。 明日は id:Toshi_Day1 さんがファイナンス系でなにか書いてくれます。 お楽しみに。
アバター
BASE Advent Calendar 2018 17日目 この記事は「BASE Advent Calendar 2018」17日目の記事です。 devblog.thebase.in はじめに はじめまして。Native Application Group の木下です。主にAndroidアプリの開発を担当しています。 今年はアプリの開発に留まらず、プロジェクトのディレクションやグロースハックといった分野にも少し手を出してきましたので、1年を振り返りながら知見などを共有できればと思います。 最近のBASEの組織 最近のBASEでは「グループ」と「プロジェクト」の二つの組織体系で業務を行なっています。 「グループ」はデザイン・バックエンド・アプリ・SREなど、スキルや分野によって分類された組織で、私の所属する Native Application Group では、日常的にスマホアプリに関する次のような業務を行なっています。 他部署からの要望にもとづく機能開発 不具合やOSのアップデート対応 新しい技術の組み込みや技術的負債の解消 開発環境の基盤づくり 新バージョンのリリース これに対して「プロジェクト」はクォータごとに目的・目標(KGI)と期限が設定され、目標を達成すべく、各「グループ」から選抜されたメンバーで構成される組織になります。同時に複数のプロジェクトに所属するケースもあります。 プロジェクトのイメージ プロジェクト名 目的 KGI プロジェクト マネージャ ディレクター デザイン バックエンド アプリ プロジェクトA プロジェクトB プロジェクトC はじめてのグロースハック 2018年の各クォータで所属した「プロジェクト」では、ディレクターかAndroidアプリエンジニア、もしくは両方のポジションに就き、特に1Qと2Qでは数値改善を目的としたグロースハック系のプロジェクトを担当しました。 グロースハックはほぼ未経験でしたので、まずは基礎知識を身につけなければと思い関連する書籍を読みました。特に参考になった2つを紹介します。 「いちばんやさしいグロースハックの教本 人気講師が教える急成長マーケティング戦略」 タイトルのとおり、初心者向けでとてもわかり易い内容でした。 「データ・ドリブン・マーケティング―――最低限知っておくべき15の指標」 紹介文の “ジェフ・ベゾスが愛読! 世界最強のマーケティング企業 アマゾン社員の教科書” に惹かれて読んでみました。プロダクトの意思決定で重要となる15の指標についての説明が、実例を交えながら書かれています。 まずはデータ収集から グロースハックでは仮説・検証を繰り返し行いますが、その前段として現状を捕らえるためにデータ集めを行いました。 ショッピングアプリ「BASE」では、Firebase Analytics でイベントログを収集して、BigQuery にインポートし、Redash を使ってモニタリングしています。社内には50インチ以上の大型ディスプレイが何枚もあり、さまざまな指標やサービスの状況をモニタリングできるようになっています。 Redashの導入・布教については過去の記事をご覧ください。 devblog.thebase.in はじめの頃は個人的にRedashではなくData Studio(今のデータポータル)を利用していましたが、グラフのレイアウト調整などが地味に面倒だったり、社内的にRedashの布教が進んでいたこともあり、途中でRedashに切り替えました。 Data Studio はダッシュボードを Google Driveのファイルとして扱え、アカウントや権限の管理が簡単だったりと良い点もありますが、日々新たなダッシュボードを追加していくとなると、多機能すぎてちょっと扱いづらいかなと思いました。 KGIからKPI、施策から効果測定まで 前述のとおりプロジェクトごとにKGI(Key Goal Indicator : 重要目標達成指標)が設定されます。KGIには最終的なゴールとなる指標が設定されるため、直接KGIを上げようとしても具体的な施策を立てるのが困難でした。このため、まずKGIを構成するいくつかのKPI(Key Performance Indicator : 重要業績評価指標)に分解して、このKPIをあげるための施策(ユーザー体験や機能の改善)を検討して実施(開発・リリース)する流れとしました。 ダイエットに例えるとこんな感じです。 KGI : (3ヶ月で)体重マイナス10kg KPI(1) : 1日の摂取カロリーを300kcal削減する 施策(1-1) : 夕食のご飯の量を50%削減する 施策(1-2) : 3時のおやつを廃止する KPI(2) : 1日の消費カロリーを300kcal増加させる 施策(2-1) : 通勤電車では椅子に座らない 施策(2-2) : 毎日5kmジョギングする 施策を実施したら効果測定を行います。リリースと同時にRedashを使ってモニタリングを開始し、KPIとKGIの動向を追います。KPIが改善されてもKGIに影響しない(仮説が外れる)こともあるため必ず両方を見ます。 改善されない場合や不十分な場合は、施策の内容を改善したり、施策をキャンセルすることもあります。ダイエットの例であれば、1ヶ月経っても体重が減らない場合は「ジョギングの距離を10kmに変更する」といった感じになります。 プロジェクトのディレクション 続いてプロジェクトのディレクションについてです。 BASEにおけるディレクターの役割については次のように考えています。 メンバーの活動を最適化して、プロジェクトが成功する確率をできる限り高めること。 プロジェクトを成功させるのはあくまで各メンバーであって、環境づくりや交通整理をするのがディレクターの役割であると考えています。ディレクターが重要な意思決定を下したり、仕様を決めたりするのは適切でないと思います。特にBASEは数字やデータに基づきシンプルに意思決定する文化のため、この考えは適していると思います。 また、ディレクター要因でプロジェクトの進行やメンバーの活動を鈍らせることは絶対にあってはいけないと考えます。1Q=3ヶ月、という短い期間で目標を達成しなければいけないため、特にこの点は特に留意しました。 ディレクターとしてやったこと ディレクターに就いた直後は、何を期待されているのか?何をやれば良いのか?よく分からず右往左往した時期もありましたが、いろいろと試行錯誤した結果、主に次のようなことをすることとしました。 プロジェクト開始前 プロダクトマネージャーからプロジェクトの目的についての背景や詳細、マストでやりたい施策についてのヒアリング 施策ごとに作成するドキュメントのテンプレート作成 主要KPIの設定 プロジェクトの立ち上げ キックオフミーティング プロジェクトの目的やKGI、プロダクトマネージャーの意向などを共有 定例ミーティングの調整 メンバー全員で施策ブレスト 施策案出し 施策の規模感や実現性の確認 優先順位付け マスタスケジュール作成 BASEでは Asana を活用しています プロジェクト中 ミーティングのファシリテーション Dailyでスタンドアップミーティング Weeklyでミーティング(進捗確認、施策の結果共有、追加施策の検討) 進捗把握とフォロー リリースや効果測定のサポート プロジェクト終了後 KPTでの振り返り 納得感と温度感 プロジェクトはKGI/PKIを達成するために活動しますが、各施策についてメンバーが納得感を持つことが重要だと考えます。 なぜそれをやるのか?プロジェクトに貢献できる施策なのか?ユーザー体験は改善されるのか・悪化しないか?...などプロジェクトの目標は共通であったとしてもメンバーごとの視点は異なり、納得感が高ければ施策の質も高めることができ、より良い結果が期待できると思います。 この納得感を高めるため、ブレストで作成した施策案リストに次のような「いいね」欄を設けて、温度感を可視化することとしました。 ミーティング中に「この施策どう思いますか?」と聞いても、声の大きい人の意見で染まったり、分からないことがあっても今更聞きづらい空気ができてしまっている場合もあり、メンバーそれぞれの納得感を確認し高めることは難しいため、カジュアルに可視化できる仕組みとしてトライしてみました。 この「いいね」で多数決することはしませんが、優先順位に多少は影響しました。中にはプロダクトマネージャーの挙げた施策でも、「いいね」数が少なく優先順位を下げることもありました。温度感の高い施策について重点的に議論を進めることができました。逆に効果が期待できそうなのに温度感の低い施策については、施策内容を掘り下げて納得感を高めにいくことができました。 測定不能 様々な施策を実施する中で、1つ大きくハマったことがありましたので紹介しておきます。 施策をリリースしたら効果測定するようにしていますが、測定できなくなる事態が度々発生しました。主な原因は2つあります。 同じKPIに影響する複数の施策を同時期にリリースしてしまった セールなどのキャンペーンやTVCMの放送と施策のリリース時期が重なった 一つ目の施策が重なる問題については、KPIが改善されてもどの施策が効いているのか特定するのが困難になります。プロジェクト内でやってしまうケースや他のプロジェクトの施策と重なるケースがあり、前者の場合はプロジェクト内で注意しながらリリースのスケジュールを策定していれば回避できるのですが、後者の場合は他プロジェクトとリリース時期を地道に調整することで回避するしかないかなと思います。 二つ目のキャンペーン等については、 KPI/KGIへの影響が非常に大きく期間も長いため、完全にお手上げとなります。社内にアンテナを張って、キャンペーンが始まる時期を早めに察知し、リリースや開発のスケジュールを調整することで防いでいくしかないかなと思っています。 Androidアプリの開発について 最後になりますが、この1年でAndroidアプリ開発もいろいろ変化しました。 CI環境の移行(Bitrise + Danger) 昨年までは Jenkins(社内のMac miniで稼働)でビルドしていましたが、今年に入ってから Bitriseへ移行しました。Bitrise を選んだのは Circle CI のようなメモリ制限(4GB)がないのと、モダンなUIでカジュアルに利用できそうで周囲でも流行っていた、という理由でした。最初の立ち上げは他のメンバーが対応していましたが、比較的スムーズに移行できたと思います。 そして、せっかくBitriseを導入したのだからもっと活用しようと思い、Dangerを導入しました。Danger を使うと、Pull Request などをトリガーとして、PRの内容をチェックしてワーニングやエラーなどのコメントを自動で表示することができます。エラーの場合はマージ不可とすることも可能です。 Danger公式サイト Using Danger with Bitrise 実際の Dangerfile は次のような内容となっていて、PR作成・更新時にチェックが走ります。 is_release = github.pr_labels.include? "[RELEASE]" # WIP warn("PR is classed as Work in Progress") if github.pr_title.include? "WIP" # PRが大きすぎる(リリース用のPRは除外) warn("Big PR, over 1000 lines") if git.lines_of_code > 1000 && !is_release # 誰もアサインされていない has_assignee = github.pr_json["assignee"] != nil warn("Please assign", sticky: false) unless has_assignee # release以外からmasterへマージ is_to_master = github.branch_for_base == "master" is_from_release = github.branch_for_head.include?("release") fail("You can only merge to the master branch from the release branch") if is_to_master && !is_from_release # ファイルの変更検知 protected_files = ["build.gradle", "proguard-rules.pro", "version.properties", ".gitignore"] protected_files.each do |file| next if git.modified_files.grep(/#{file}/).empty? message("Changes have been made to the #{file} file") end Androidチームでは、次のようなブランチ運用を行なっています。 リリースの時期とスコープを決めてreleaseブランチを作成 feature ブランチを作成して開発 release ブランチへPull Request(WIPで早めに出していつでもレビュー可能に) レビューが完了したらマージ release ブランチでQAが完了したら masterブランチへPull Request master へマージすると同時に自動で本番ビルド開始 リリース このように develop ブランチが存在しないためシンプルな運用が可能です。しかし master をデフォルトブランチに設定していることで時々事故が起きていました。通常 Pull Request は release に向けて作成するべきですが、誤って master に向けて作成してしまうことがあり、レビューでも気づかれずそのままマージしてしまうことが何度か発生しました。本番ビルドが走ってしまったり(Publishは自動化していないのでセーフですが)、Revertする手間が発生したりと、地味に面倒な作業が発生します。これを防止するためDangerにチェック項目を追加してPR先が master の場合はマージ不可することで、このような事故は発生しなくなりました。 コードレビュー必須化 Androidチームのメンバーも増え、品質を維持したり技術的負債を増やさないためにも昨年末からコードレビューを必須とし、メンバー全員からapprovedされるまでマージできないルールとしました。 自分自身、前職くらいからコードレビューをやり始めてはいましたが、仕様を満たしているかのチェックがメインであまりコードレビューと言えるものではありませんでした。必須化した直後は要領よくレビューができずに、場合によってはほぼ「ノールックLGTM」していた時もありましたが、最近ではレビューの質もあがり主に次のような点を見るようにしています。 将来負債になったり不具合の原因となりそうな実装がされていないか MVVMモデルに則した実装となっているか Nonnull / Nullable の区別は適切か スコープ関数を利用したkotlinらしいコードになっているか kotlinで Utilsクラスや Stream を利用していないか また若いエンジニアからも鋭い指摘をもらうことがあり本当にありがたい限りです。Kotlinだとこんな書き方もできますよ、といった感じで知識を共有する場にもなったり、チーム開発&コードレビューって素晴らしいな〜と感じるようになりました。 ちなみにレビューの負荷軽減・レビューによる手戻り削減のため、作業を始めたらなるべく早く WIPで Pull Requestを出し、余裕のあるときにレビューするようにしています。突然「急ぎでレビューお願いします」と言われても、すぐに時間が取れず雑にLGTMしたり、ほんとは指摘したいけど修正しているとリリースに間に合わないから今回は指摘しないでおこう、など良くない状況が起こり得るため早めにレビューできる運用を心がけています。 TLS1.2対応とAndroid4.xサポート終了 BASEではセキュリティ対策の一環として、今年の6月にサーバーをTLS1.2へ移行する計画があり、これに合わせて Android4.x のサポートを終了することとなりました。 1ヶ月前からアプリ内のお知らせやGoogle Play のアプリページに告知を表示して、Android4.x の端末からは(TLS1.2に対応している)ChromeブラウザのWebページからご利用いただくようお願いしていました。(BASEの場合、アプリだけでなくWebページからも商品が購入できる点は強みだと感じました。) また、移行したタイミングで4.x端末でアプリを起動すると、サポートを終了した旨のメッセージを表示して起動を中断する仕組みを、早い段階で仕込んでいました。 普通であれば要求を受けた何かしらのAPIがOSのバージョンをチェックして4.xならエラーを返す、という設計を考えると思いますが、TLS1.2未対応のクライアントからはAPIに一切接続することができなくなるため、アプリ起動後最初のAPI接続の前に上記のような仕組みを入れることで、アプリがクラッシュしたり「ネットワークエラー」のような意味不明なメッセージを表示することがないようにしました。この仕組みはFirebase RemoteConfg を利用して実現しています。 結果として、一部のユーザー様にはご迷惑をおかけしましたが、大きなトラブルもなくスムーズに移行することができました。 Kotlin化 BASEアプリのKotlin化進捗状況です。 もともとオールJavaでしたが、2017年のGoogle I/OでKotlinの正式サポートが発表されたのをきっかけにKotlinの導入をはじめました。 ひとまず、 新機能/クラスはKotlinで実装しよう (あとは余裕あるときに徐々にやっていこう...) なノリで移行を続けて1年半が経ちましたが、思ったほどKotlin化が進まず、2020年になってもJavaを書いてるのは嫌だなー(バージョン1.1のころからJavaに触れている身としては切実です)と思い、 少しでも修正するJavaファイルはKotlinにコンバートする というルールを最近になって追加しました。 来年中にKotlin 100%を達成できるよう頑張りたいと思います。 AndroidX移行 AndroidXの移行については、 このスライド を見て詳細を把握し、直後にIssueを立てAndroid Studio3.2(正式版)がリリースされたタイミングで対応する予定でした。今後公開されるドキュメントはAndroidX前提で書かれ、AndroidXでしか利用できない機能・クラスも増えてくるだろうと考えて、放置していても負債にしかならいと判断したためです。 AndroidXは皆さんお馴染み Support Library の改良版です。Support Library は9月にリリースされた Revision 28.0.0 で終了しており、今後は AndroidX へ移行する必要があります。 Android Studio 3.2 以降では移行ツールが用意されドキュメントも整備されていますので、まだ対応されていない皆さんには早めの対応をお勧めします。 AndroidX Overview Migrate an existing project using Android Studio 実際に対応したのは他のメンバー(Android歴1年未満の若手エンジニア)で、QA含めて2週間くらいで完了し10月上旬にリリースしましたが、リリース後も特に問題はなくスムーズに移行できたと思います。もちろんコードレビューもしっかりやりました。 まとめ 2018年は、Androidアプリの開発だけでなくプロダクトやチームの成長にも熱中でき、SIer・受託開発歴の長い自分にとっては大変実りのある一年となりました。スタートアップだからこそできる貴重な経験だと思います。 来年もたくさん新しいことにチャレンジしていきたいと思います! 明日はビール部部長の氏原さんです!
アバター
これは「BASE Advent Calendar」16日目の記事です。 こんにちは、BASEのDesign Groupに所属している吉岡です。 先日BASE BANK株式会社初めてのプロダクトとして即時に資金調達ができる金融サービス「 YELL BANK 」をリリースしました。個人的にお金にまつわるデザインは初めての経験ということもあり、難しかったのですが、LPではAfterEffectsで作ったアニメーションをCanvasやSVGアニメーションにできるプラグインを使って表現しました。 今回はせっかくのアドベントカレンダーなので、下記の様なHolidayAnimationを書き出してみようと思います。 環境設定 Bodymovin をインストール creative.adobe.com プラグインインストールのためのzxp-installerもダウンロードします aescripts.com Lottieアニメーションの Bodymovin プラグインをダウンロードして、インストールする github.com bodymovinを解凍してzxpファイルをzxpインストーラーにドラッグしてインストールします。 AfterEffectsに拡張が入っているか確認する 問題なくインストールできれば、AfterEffectsのウィンドウ/拡張機能にBodyMovinが入っているはずです。 XDでデザインを作る 今回はテキストアニメーションを描いていこうと思うので、Adobe XDでまず描きたいテキストを配置します。この際にアートボードサイズが最終ブラウザに書き出すサイズになります。 テキストを配置したら、ファイル > 書き出し > After Effectsで書き出します(最近できた機能です。illustratorよりサクッとAfter Effectsに書き出せます。) After Effectsでアニメーションを作る アニメーションを作っていきますが、Lottieを使う注意点を先に記載します。 - After Effectsのエフェクトは使えないと思ってていい - Expressionも書き出さないと使えない - グラデーション効かない といった具合です。パスアニメーションができるよ、程度の認識で良いかもしれません。After Effectsで使える機能は こちら で確認できます。 前提が終わったところで...アニメーションを作っていきます。 まずはXDで作っていたテキストを、アウトライン化してシェイプとして配置しておきます。 今回は筆記体テキストが流れていく様なアニメーションを作りたいと思うので、パスに合わせてモーションが動くアニメーションを作っていきます。好きなシェイプを作り、テキストをなぞる様に位置のkeyframeを打っていきます。トランスフォーム > 自動方向でパスに沿って自動方向に設定します。こうすることでパスに沿ってシェイプが回転します。ここからは好きな様にパスを変形させてkeyframeを打っていきます。 パスに添わせたアニメーション部分はこんな感じです。 アルファマットでテキストを表示する パスに添わせたアニメーションに合わせて、テキストを表示するためのシェイプもパスkeyframeを描きます。 テキストにアルファマットでマスクした状態にします。 これでアニメーションは完成です。 JSONに書き出す アニメーションが完成したら、JSONファイルに書き出していきます。 ウィンドウ > 拡張機能 > Bodymovinを選びます。 selectedでコンポジションを、Destination Folderに書き出し先ディレクトリを選びます settingsでは今回はこの設定で書き出します。 - Glyphs(もしフォントが残っていてもシェイプにしてくれます) - Hidden (マスクなどを使っていると必要です) - Demo (HTMLに雑にしてくれるので確認が楽でおすすめです) 他にも、画像をJSONにincludeしてくれるAssetsの項目もあるので適宜必要あれば設定します。 確認してみる 書き出しフォルダにindex.htmlが生成されるので確認してみると... 作った通りのアニメーションが表示できています! 中身がどうなっているのかというと... AfterEffectsのレイヤーがちゃんとSVGのpathになって、transformされるのがわかります。 Lottieを使ってみて グラフィックだけでもholidayっぽさはあるのですが、アニメーションをつけることでより情緒的な抑揚をつけることができるので、デザイン表現が簡単に広げられるLottieはとても使いやすいプラグインだと思います。 今までYoutubeなどで上げていた動画より、サクサク動きます! これを機に、アニメーションまでデザインしてみては...! 明日はAndroid エンジニアの木下さんです!
アバター
はじめに これは「BASE Advent Calendar 2018」15日目の記事です。 devblog.thebase.in こんにちは、Backend Engineer Groupの 菊地陽介 です。今回は、BASEの育休エバンジェリストとして記事を書きたいと思います。今年の8月8日に第一子(綾瀬はるか似の娘)が生まれ、その後BASEの男性社員としては初めてとなる育児休業(以下、育休)を1.5ヶ月ほど取得しました。 育休取得直後に娘の心臓に先天性の疾患があることが分かり、一般的な赤ちゃんの倍くらい世話が必要だったので私が育休を取って妻と2人で育児をすることができたことは大変ありがたかったです(その後手術を行い現在は回復の方向に向かっています)。 なにより育休期間中の1.5ヶ月は娘の成長を間近で見ることができ、私の人生において生涯忘れないであろうかけがえのない日々となりました。そこで私が今回育休を取得して気付いたこと、思ったことを日本の全パパにお伝えしたい。 日本の男性社員が育休を取りにくい理由の一つとして、前例がまだ少なく情報があまりないということが挙げられると思います。今回育休に関する様々な知見を得ることができましたので紹介します。本記事をきっかけに育休に対する理解を深められたり、これまでより柔軟に考えてもらう機会になれたら幸いです。 (注) - 制度の内容は育休を取りやすい方向に変わっているので本記事で述べているものと現在の制度が異なっている可能性があります。 - 本記事は育休について大まかに知ってもらうことが目的なので詳細については言及していません。 日本のパパの育休について 私が育休を取得しようか検討する際に知りたかった情報を紹介します。 一ヶ月以上の育休取得率は1%以下 パパの育休取得率は年々上がってきてはいるもののそれでも平成27年度時点で2.65%程度しかありません。さらに5日未満しか育休を取得しない人が56%を占め、一ヶ月以上の育休を取っている割合は20%以下です。つまり一ヶ月以上の育休を取っているパパは日本には100人に1人以下しかいないというのが現状です。 (厚生労働省「 資料 「平成 27 年度雇用均等基本調査」の結果概要 」より) 休業前の手取り賃金の8割がもらえる 育休を取得しない理由の一つとして、育休期間中の収入が0になると思っている人が多いのではないでしょうか。その心配はいりません。雇用保険の育児休業給付金制度があります。(※支給要件があります)手取り賃金で比べると約8割が支給されます。下記資料が分かりやすかったです。ちなみに メルカリ さんのように育休期間中の給与を100%保障する会社もあるようです。 (厚生労働省「 育児休業給付金の資料 」より) ※その他にも健康保険から支給される「出産育児一時金」や「出産手当金」等があります。(※こちらも支給要件があります) 産後一年の間で取得可能、また延長も可 育休は子供が産まれてすぐに取得しなければいけないものではありません。出産のタイミングでは自分が関わっているプロジェクトが忙しかったり、業務の引き継ぎがたくさん必要で育休を取りにくいという場合があるかもしれません。しかし「子供が産まれてから1年の間であれば取得可能」ということであればその間で育休を取れるように調整することは難しくないのではないでしょうか。 また、産後一年以内であれば育休を延長することもできます。私の場合当初1ヶ月の予定でしたが、育休取得後に娘の心臓に疾患が見つかり検査や入院などが必要となったため半月ほど延長しました。 私の育休 育休を取得するまで 上司に伝える 出産予定日の半年ほど前に上司に「1ヶ月くらい育休とりたいんですけど」と週に1度行われている1on1ミーティングの際に相談してみました。 このとき嫌な顔されるといった心配はまったくしておらず、「お、いいね!ていうか一ヶ月だけでいいの?もっと取った方がいいよ!」と言われるほどでした。 出産予定日前後は自分がいなくても業務に差し支えがないように配慮してもらいました。感謝です。 チームメンバーに伝える チームメンバーには育休を取る一ヶ月前くらいに報告しました。 育休を取得しない理由の大きな理由の一つとして、自分が休むと会社が回らなくなってしまうと心配してしまう人が多いのではないでしょうか。もしそう思うのであれば本当に心配しなくてはいけないのは、自分がいないと会社が回らないほどに属人化してしまっている状況です。私の場合は属人化している業務がほぼなかったため、引き継ぎは隣の席の @tenkoma に15分ほど説明しただけでした。 赤ちゃんはいきなり産まれてくるわけではありません。自分も父になるんだという気持ちが湧いてから産まれるまでに半年以上の猶予があると思います。その間に自分の業務をチームのメンバーができるように引き継ぎを行い、気持ちよく育休を取得できるようにしたいですよね。 (ちなみに自分が休んでいても何一つ問題なく会社が回っていると寂しい気持ちになります) 申請の書類を提出する 育休の申請については、育休を取得する前に会社に簡単な申請書を提出し、あとの手続きは会社でやってもらえたのでとても簡単なものでした。 育休中 育休はバケーションじゃない 育休前は少なからず下記のような気持ちがありました。 知性を感じさせるパパを目指して自己啓発本をたくさん読もう カッコいいパパを目指して毎日筋トレして体を鍛えよう 子供に尊敬されるパパを目指して国旗とか覚えよう etc 結果的に何一つとしてできませんでした。 育休期間中に育児以外のことをする時間はないと思って間違いないと思います。おそらく日本では育休をバケーションのように考えている人が少なからずいらっしゃるようで、育休を取得することに対して後ろめたさを感じ、取得に踏み込めない人が多いのかなと感じます。 育休≠バケーションです。本音を言うと私にとって育休は仕事をしてるよりしんどかったです。 ママの期待値を調整する 産後クライシスという言葉があるように、出産を機に夫婦の関係性が悪い方向に大きく変わることも多いようです。 出産直後はホルモンバランスが崩れネガティヴ思考になったり、育児に対して過剰な責任を感じてしまう母親が多く、期待してるような行動を父親が取ってくれないと苛立ちやすくなってしまうようです。特段穏やかな私の妻に限ってそれはないと思っていたのですが甘かったです。 育児中の母親は父親に求めるハードル(期待値)が高くなりやすい一方で、世の多くの父親はそれをなかなか超えてこないので苛立ちが生じるのだと思います。ですので、ハードルを下げましょう。 具体的には「オムツ交換とミルクを作るのはパパ、お皿洗いと料理の準備はママ」といったように家事や育児の役割分担をできる限り明確にすることが重要だと思います。例えば「お皿洗いは気が付いた方がやるようにしよう」としておくと、「私は寝不足で疲れてるんだからパパが洗ってよ」とパパがお皿を洗うことを期待されることがあります。しかし事前にお皿洗いはママの役割と明確にしておけばそのような期待は起きないでしょう。逆にお皿洗いはママの役割としているのにパパがお皿を洗ったら感謝されるものです。 結果的にやってることは一緒でも期待値の調整次第でママからの評価は大きく変わるものです。 仕事と一緒ですね。 考え方が変わった 育児をすることで色々考え方が変わったなと感じます。私はたくさんある育児の中でオムツ交換が一番好きです。下記写真のように赤ちゃんのなされるがままにお股を広げている無力な様がたまらなく可愛いく思うのです。 あの人怖いな、苦手だな、堅物だなとこれまでは避けていたような人に対しても、「昔はオムツ交換してもらってたんだな」と思うと微笑ましく感じられるようになり、以前よりも余計な感情なくニュートラルに人と接することができるようになったと感じています。 また、育児がこれほどまでに大変なんだと実感することで自分を育ててくれた両親に対しての感謝の気持ちが強くなりましたし、世の中にいるパパママはみんなすごいなと尊敬の気持ちを抱くようになりました。 育休が終わってから 復帰初日は転職初日のような緊張感がありました。1.5ヶ月間の育休でしたが個人的には1年くらい休んでいた感覚でした。私が育休を取っている間に次のような変化がありこれぞベンチャー企業だなと思いました。 渋谷の2フロアに分かれていたオフィスから、六本木の高層ビルの37階に引っ越ししていた 新入社員がたくさん増えてた BASEの男性社員として初となる私の育休をきっかけに多くの男性社員から「次に子供が生まれる際には自分も育休を取ろうと思う」というふうに声をかけられました。 今後も育休エバンジェリストとして育休を取得することの意義を布教していきたいと思います。 出産&育児で得た知見 本記事の育休を勧めるという目的からは話が逸れるのですが、出産&育児の際にいくつか知見を得たので共有します。 日用品にかかるお金はけっこう節約できる 先輩パパママから「子供ができるとオムツ代とかミルク代がバカにならないよ!」とよく聞かされていました。 実際はそんなことありません。 そうです、ふるさと納税です。ふるさと納税を有効に使えばオムツ(メリーズ、ムーニーマン、グーン等なんでもある)、おしりふき、ミルクetcほとんどなんでも揃えることができます。ぜひ活用してみてはいかがでしょうか。 おすすめのアプリ 様々なアプリをたくさん比較した上で厳選したというわけではないですし、一番メジャーなものを使っていただけなのですが下記で紹介するアプリは大変素晴らしく感動したので個人的におすすめさせてください。 トツキトオカ 「 トツキトオカ 」は、夫婦で共有できる妊娠記録・日記アプリです。 日々アプリの中の赤ちゃんが成長していき、また話す言葉もグッとくるものなので父親になるんだなという実感が徐々に湧いてきました。 また妻が毎日このアプリで日記を更新していたのですが、口には出しづらい心配ごとなどを書いていたりして妻の心情を理解するのに役立ちました。 ( トツキトオカ 公式HP より) みてね 「 みてね 」は、子供の写真を家族で共有することができるアプリです。 スマホはLINEくらいしか使いこなせていなかった私の父と母もこのアプリなら使いこなせるくらい、UIUXが優れていて使いやすいです。 また、フォトブックやDVDをすごく簡単に作成することができます。しかもとても安価に作成できるので運営会社が今後も継続していけるのか心配になるほどです。 ( みてね 公式HP より) まとめ 本記事を読んで育休を取ってみようかなという気持ちになっていただけたなら幸いです。 私が育休をとるにあたって業務の調整を行ってくれた上司やフォローをしてくれたチームメンバー、復帰後も温かく迎えてくれたBASEの社員みんなにこの場を借りてお礼を伝えたいと思います。 本記事を読んで少しでも伝わったなら嬉しいのですが、BASEはみんないい人でとても働きやすい良い会社です。 BASEってどんな会社なの?会社に遊びに行ってみたい!育休の話もっと詳しく聞きたい!財テクの話が聞きたかった!と思っていただける方がいらっしゃればぜひ 私 までメッセをいただければと思います! 明日はデザイナーの吉岡さんがデザイン表現を広げるアレコレについて書くようです、ぜひご覧ください!
アバター
この記事は、「BASE Advent Calendar 2018」の14日目の記事です。 devblog.thebase.in こんにちは!Design Groupに所属している森( @ mrkzk )です! リードエンジニアのお兄さんに「森さん、寿司食いたくないですか?」と聞かれ「もちろん、食べたいです。」と答えたらアドベントカレンダーブログを書くことが決定していました!お寿司は隠語だったのでしょうか?びっくりです! では早速、タイトル通り デザイナーの私が初めてプロダクトのコードをコミットしてみたお話 をします。 どうしてコードを書くことになったの? 私の普段の業務はアプリのUIデザインなのですが、ときどきWebのクリエイティブ作成にも関わることがあり、いつもクリエイティブを作ったのちに「お願いします!」とこのようにエンジニアの方にお渡ししています。 今回は、既存バナーのUIやショップ数が古かったので更新するために差し替えが必要だったのですが、「お願いします!」と言いながら、画像の差し替えくらい自分でできたらな、、と思っていたところこのような流れが・・・ 「こんな綺麗な流れってあるんだ・・・」と感心しつつ、探り探りでやっていくことに・・・ まず、作成したクリエイティブをステージングへ、そして本番へアップロードしなければいけません。 そこで噂には聞いていた画像アップローダーの出番です! 画像アップローダーの実装に関しては、先日エンジニアリングマネージャーの加賀谷が記事に書いています! devblog.thebase.in 画像アップローダーくんの使い方 Slackの該当チャンネルに作成したクリエイティブを投稿する Slackで @image-uploader hey と話しかける   画像アップローダーくんからお返事がきたので快く yes を選択 すると・・・ ステージングにアップロードできちゃいました!こんな簡単に・・?と疑っていると、今度はタコとネコのハーフからお返事が来たので快く yes を選択。 すると・・・ できました!差し換え用のクリエイティブを本番にアップロードすることができました。すごい! と、ここまでは画像アップローダーくんに助けられていましたが、ここからは一人の戦いです。 OSの出し分け 今回私が作成したクリエイティブは、アプリへのダウンロード導線バナーです。 OS別にバナーを作成しているので、iOSユーザーには左のiPhone端末バナー、そしてAndroidユーザーには右のAndroidの端末バナーを出したいのです。 ところが、コードの書き方が全くわかりません。 とりあえず OS 出し分け で検索してみると、「JavaScriptで簡単にUA判定する方法」に関する記事が出てきました。どうやらUA判定というものがあって、これを使えばiOSかどうかがわかるらしいので、UAを利用してiOSを判定するコードを探しました。 こちらです。 var ua = navigator.userAgent var isIOS = ua.indexOf( "iPhone" ) >= 0 || ua.indexOf( "iPad" ) >= 0 || navigator.userAgent.indexOf( "iPod" ) >= 0 こちらを利用して、実際に画像を出し分けるコードを書いてみます。 imgタグはわかっていたので、このソースを切り替える方法を調べていくと「getElementByIdを使ってソースを書き換えると良い」とあったのでとにかく書いてみました。 < script > var ua = navigator.userAgent var isIOS = ua.indexOf ( "iPhone" ) >= 0 || ua.indexOf ( "iPad" ) >= 0 || navigator.userAgent.indexOf ( "iPod" ) >= 0 ; var img = document .getElementById ( 'appBannerImg' ) if ( isIOS ) { img.src = "//static.thebase.in/img/u/U1MK212HY/FER5CBE2D.png" } else { img.src = "//static.thebase.in/img/u/U1MK212HY/FERP402M8.png" } </ script > これでpushしてみると・・・ちゃんと動いてます!出し分け成功! なんとかこれをプルリクエストまで持っていくことができました!なんでしょうか、この達成感は・・!! プルリクエストー!!と舞い上がっているところに間髪入れずリードエンジニア兄さんからのつぶやき↑が聞こえてきました。コードを少し書くだけでも一苦労だったので正直勘弁してほしいなと思ってしまいましたが、どうせなら!と querySelector に書き換えることに。 - var img = document.getElementById('appBannerImg') + var img = document.querySelector('#appBannerImg') getElementById の部分を querySelector に変更し、imgタグの前に # をつけるだけ! これがイマドキなんですね(getElementByIdの方が響きはイカしてると思いますが) こうして無事リードエンジニアの兄貴からOKが出ました!リリースです🎉 おしまい ここまでの流れを簡単に書いてきましたが、実際はコマンド一つを実行するにも調べながら、質問しながら、とかなり苦労しました。 それでもターミナルがガガガーっと動くのは楽しいし、自分の制作物をエンジニアさんにお任せするのではなく、最後まで責任持って本番環境に届けることに気持ちの良さと達成感を覚えました! 私のようにこれからは一通り自分でやってみるぞ!!というデザイナーが増えると嬉しいです。 ちなみに Twitterトップ でLINEスタンプ販売中なので見てみてください! 明日の担当はBASEのイクメン・菊地さんです!
アバター
BASE Advent Calendar 2018 (13日目) この記事は、「BASE Advent Calendar 2018」の13日目の記事です。 devblog.thebase.in Backend Engineerの沖中 ( @okinaka ) です。 読者のみなさんはテストを書いてますか?テストが面倒くさいとか思ってませんか?(私はたまにあります) そんな時、モチベーションをあげるには、どのような工夫をしていますか? 私の場合、カバレッジ計測の結果のレポートがとても役に立っています。 レポートを眺めると、視覚的に 「どの行が実行された」とか 「カバレッジ率が◯%」だとか 「ここ複雑だけどテストがないクラスがあるよ」など、 いろいろ気づきがあります。 「ここマズイな、テスト書いて確認しなくちゃ!」という気持ちになるのでとても重宝しています。 とてもいいツールだと思うのですが、残念ながら BASE社内でもまだ十分に活用されていないのが現状です。ですので、この記事をきっかけに、広めていければいいのではないかと期待しています! 現状ではカバレッジレポート出力が時間がかかる問題があるのですが、今後、自動生成する仕組みを用意できればと考えています。 カバレッジレポートについて BASEでは、主にCakePHPでサービスが構築されており、ユニットテストも、若干手を加えていますが基本的にはCakePHPに用意された仕組みを利用しています。カバレッジレポートは、その機能を利用して生成しています。 カバレッジについての簡単な説明は、 CakePHP クックブック をご覧ください。 (内部的には PHPUnit を利用しています。詳細は こちら ) カバレッジレポートには出力形式がいくつかあるのですが、今回はモチベーションアップが目的なので、人が見てわかりやすいHTML出力を紹介します。 出力されるHTMLページは大きく分けて3つに分類されます。 各ディレクトリ内のファイル一覧 (index.html) ファイル毎の大まかなカバレッジ状況を一覧で確認できるページ *1 ファイル一覧(index.html) 各ファイルのカバレッジ詳細 (PHPファイル名.html) どの関数・行がテストされたかなど詳細を確認できるページ 次にどんなテストが必要かを考える際に役立ちます カバレッジ詳細(PHPファイル名.html) ダッシュボード (dashboard.html) 以下のカバレッジ状況を俯瞰的に確認できるページ クラス・メソッドのカバレッジ率 (Coverage) コードの複雑度 (Complexity) の分布図 カバレッジ率の低い順のクラス・メソッド一覧 リスク (CRAP値) の高い順のクラス・メソッド一覧 全体の状況を把握したり、次にどのファイルをテストすべきかをざっと見るのに便利! ダッシュボード(dashboard.html) テスト作成とカバレッジレポート出力 では、実際にレポートを出力して内容を見てみましょう。 まず最初に、とあるメソッドに対してテストを1つ書いてみました。 <?php public function testView () { // テスト対象を実行 $ this -> testAction ( ' /posts/view/1 ', [ ' method ' => ' get ', ' return ' => ' contents ' ]) ; // とりあえず、ステータスコードの確認 $ this -> assertSame ( 200 , $ this -> controller -> response -> statusCode ()) ; // その他、なんらかの結果の確認... } この時点で、カバレッジレポートを出力してみます。レポートを見ると、どうやら一部実行されていない行があるようです。 (注: 緑の部分 がテストされた行で、 赤い部分 が未テストな行です。 赤い 部分をなんとか消したくて、ウズウズしてきますね!) カバレッジ詳細(テスト1回目) 未テストだった行を確認してみると、 $id が未指定 ( null ) だった場合と、 データーベースに未登録な $id だった場合の処理がテストされてないようです。 このレポートを受けてテストケースを追加してみます。 <?php /** * @expectedException NotFoundException * @expectedExceptionMessage Invalid post */ public function testViewで、IDが未指定だった場合は例外発生 () { $ this -> testAction ( ' /posts/view/ ', [ ' method ' => ' get ', ' return ' => ' contents ' ]) ; } /** * @expectedException NotFoundException * @expectedExceptionMessage Invalid post */ public function testViewで、未登録なIDを指定した場合は例外発生 () { $ this -> testAction ( ' /posts/view/999 ', [ ' method ' => ' get ', ' return ' => ' contents ' ]) ; } 結果がこれ。 カバレッジ詳細(テスト2回目) やりました! 赤かった ところが 全部緑色 に!これで安心です。 ここで、注意点があります。 全部緑色 になって喜んでいましたが、 緑色の行 を増やすよりもむしろ テストの内容 の方が重要です。 たとえテストが実行されたとしても、ちゃんと動作を確認していなければ意味がありません。あくまで、モチベーションを高め、テスト状況を確認するためのツールと捉えていただければと思います。 明日はデザイナーの森さんです!お楽しみに! *1 : 注: CakePHP 公式のクックブックの チュートリアル を元に、独自のテストを実行した結果を表示しています。
アバター