ホーム ブログ ページ 10

Flutterによるアプリ開発 <Firebase連携編>

0

ゲームデザイン部中村です。

引き続きFlutterによるアプリ開発について記載していきます。前回・前々回については以下のリンクからご覧ください。

Flutterによるアプリ開発<導入編>

Flutterによるアプリ開発<ウィジェットレイアウト編>

Flutterの導入とウィジェットレイアウトについて説明してきましたが、SNSやショッピングサービスなどではアプリのみですべてのサービスを完結させることはできません。サーバ上にユーザ情報を格納し、SNSではサーバから友達の情報を取得しなければならず、ショッピングサービスでは商品の在庫があるかをサーバに問い合わせなければなりません。このようなとき、サーバ側の環境構築をすべきなのですが、非常に面倒です。

そこで今回は幅広くサーバ側にサービスを用意している、Flutterと非常に相性の良いFirebaseとの連携を行います。

今回は画像多めでお送りします。

Firebaseとは

Googleが提供するアプリケーション開発プラットフォームです。代表的な6つのサービスがあり、その特徴は「クロスプラットフォーム」「インフラ構築不要」ということにあります。

Authenticationはユーザ認証を手軽に導入できます。メール/パスワードだけでなく、Google・Twitter・Facebook・Appleなどのユーザ認証を一つのソースコードで行うことができます。

CloudFirestoreはスケーラブルなNoSQLデータベースです。MySQLやPostgreSQLとは異なり、データを保存するドキュメントがあり、コレクションの中に複数のドキュメントが存在します。

RealtimeDatabaseはJSON形式のデータを保存するNoSQLクラウドデータベースです。保存されたデータは接続しているすべてのクライアントで同期され、リアルタイムに更新されます。

Storageは写真や動画などを保存、提供するストレージサービスです。

HostingはWebコンテンツホスティングサービスです。Webアプリ、静的コンテンツ、動的コンテンツをCDNに配信することができます。

CloudFunctionsはサーバレスにHTTPSリクエストをトリガーとしてバックエンドコードを実行します。マネージド環境で実行されるため、個別のインフラ構築が不要です。

以上6つのサービスから、今回はCloudFirestoreにデータを格納しStorageに画像を保管するという流れを説明していきます。

Firebaseプロジェクトの作成

まずはFirebaseコンソールへ移動しましょう。

「プロジェクトを追加」ボタンから作成を開始します。

「まずプロジェクトに名前をつけましょう」と表示されるので今回は「mTest」と名付けました。「続行」します。

「このプロジェクトで Google アナリティクスを有効にする」のチェックがありますので、ONのままにして「続行」します。

「Google アナリティクスの構成」では「新しい構成」から名前をつけ、アナリティクスの地域を日本にしました。

以上でプロジェクトが作成されます。

iOS構成設定

プロジェクト画面が開いたら、iOSでFirebaseを利用するための構成を進めます。

「アプリにFirebaseを追加して利用開始しましょう」からiOSを選択します。

「アプリの登録」ではバンドルIDを登録します。今回は「com.sample.mtest」としました。その他の項目は空欄で「アプリを登録」。

「設定ファイルのダウンロード」が表示されますので、GoogleServices-Info.plistをダウンロードします。SDKの追加、初期化コードの追加は行いませんのでそのまま「次へ」と進み「コンソールに進む」で完了です。

CloudFirestoreの初期設定

Flutterで表示するための仮データを作成していきましょう。

まずは左側メニューからCloudFirestoreを選択し、「データベースの作成」をクリックしましょう。

データベースの作成では「テストモードで開始する」にしておきます。作成後にセキュリティルールを設定しない限り30日間ユーザ認証なしに誰でも参照できるようになるので、ここままサービスリリースできない点はご注意ください。

「CloudFirestoreのロケーション」はasia-northeast1にしておきます。テストのうちは特に気にする必要はありませんが、普段から同じロケーションに設定しておくと忘れなくて良いと思います。

しばらく待つとデータベースが作成されるので、「コレクションの追加」を行います。今回は仮データとして食べ物を5つ用意します。

必要なデータとしては「name」「price」「image」を用意します。imageには後で用意する食べ物画像のファイル名を指定します。

同じ要領でうどん、パスタ、カレーライス、ピザを用意しました。

Storageの初期設定

続いてStorageに食べ物の画像を設置します。こちらはすでにファイルストレージとして利用できるようになっていますので、「ファイルをアップロード」から5枚の食べ物画像をアップロードします。これらの画像はいらすとやさんからお借りしました。

また、今回はFirebaseAuthを利用したユーザ認証については省略しているため、Storageのルールを以下のように編集します。これによって、ユーザ認証なしでStorageのファイルを読み書きできます。

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}

FlutterとFirebase連携

Firebaseでの仮データができたのでFlutterからFirebaseにアクセスするための設定を進めていきます。

FlutterにFirebaseSDKを導入

ウィジェットレイアウト編でも登場したpubspec.yamlにプラグインを記述します。

dependencies:
  flutter:
    sdk: flutter
  http: ^0.12.2
  # 以下を追加
  firebase_core: ^0.5.0
  cloud_firestore: ^0.14.0
  firebase_storage: ^5.2.0

pubspec.yamlに追記をするとホットリロードが動作するので問題なくアプリが動くことを確認します。

続いて、FirebaseにバンドルIDをcom.sample.mtestと登録したので、アプリ側のバンドルIDも変更します。FlutterアプリはVSCodeからプロジェクトを生成すると自動でcom.example.{プロジェクト名}というバンドルIDに設定されます。そのため、VSCodeの文字列検索からこのバンドルIDを探し、全て差し替えます。

続いて、iOS構成設定でダウンロードしたGoogleServices-Info.plistをプロジェクト内に配置します。このファイルにはiOSアプリからFirebaseへアクセスするための認証情報が含まれています。その内容はFirebaseのプロジェクト毎に異なるので注意してください。

また、このファイルの追加にはXCodeが必要です。MacのFinderからプロジェクトを開き、ios/Runner.xcodeprojをダブルクリックしてXCodeを起動しましょう。配置位置は以下の画像を参照してください。

FlutterにてFirebaseからデータを取得する

初期化コード

以上でFirebaseとの連携準備は完了しましたので、ソースコードの方を編集してFirebaseからデータを取得しましょう。

まずはFirebaseを利用するための初期化を行います。main.dartの上部でFirebaseをimportします。

~~~
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart' as cloud_firestore;
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;

これら3行でFirebaseのコア、Firestore、Storageをimportできます。FirestoreとStrageについてはasオプションで別名利用できるようにしています。

さらに、もともとあったvoid main()関数を以下のように書き換えます。

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

main関数をFutureにすることで、内部でawaitが使えるようになります。これによって、アプリの起動直前にFirebaseの初期化を行ない終了まで待つことができます。ただし、アプリが起動しないとFlutterで用意されたメソッドが呼び出せないため、WidgetsFlutterBinding.ensureInitialized();でFlutterの機能を呼び出せるようにしています。これはおまじないと思っていただいて問題ありません。

ここまでの書き換えではまだFirebaseの機能を呼び出していないため、前回作成した天気のリスト表示が同じ用に表示されることを確認してください。

CloudFirestoreから食べ物リストを取得

続いて、CloudFirestoreからデータを取得してきましょう。Scaffoldを以下のように編集します。

Scaffold(
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: StreamBuilder<cloud_firestore.QuerySnapshot>(
      stream: cloud_firestore.FirebaseFirestore.instance.collection('items').snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) return LinearProgressIndicator();
        return ListView(
          children: snapshot.data.docs.map[1]e)=>ListTile(
            title: Text("${e.get('name')}"),
            subtitle: Text("${e.get('price')}円"),
          .toList(),
        );
      },
    )
  )
);

ここではStreamBuilderが登場します。

ウィジェットレイアウト編ではFutureBuilderを利用してHTTPレスポンスを画面に描画しました。FutureBuilderは一度の呼び出し結果を待ち、レイアウトに反映します。

それに対してStreamBuilderstreamに指定したsnapshotに変更がある度、自動でレイアウトに反映します。CloudFirestoreはこの機能を利用してデータの変更を検知しレイアウトを更新できるようになっています。

上記Scaffoldの書き換えによって以下のようなレイアウトができたと思います。

それでは実際にStreamBuilderの効果を確認しましょう。ブラウザのCloudFirestoreとiOSシミュレータを画面上に並べて表示し、食べ物名や金額を編集してみましょう。ブラウザでデータを編集すると即座にiOSシミュレータに反映されることが確認できます。

Storageから画像を取得

CloudFirestoreに用意した食べ物について、それぞれのアイコンを表示するためにStorageから画像を取得しましょう。

アイコンのファイル名をCloudFirestore内のデータにimageとして指定してあるため、このファイル名でStorageに画像の問い合わせを行います。まずはHTTPリクエストで画像を表示するために以下のプラグインを追加します。

dependencies:
  ~~~~
  cached_network_image: ^2.4.1

また、このプラグインをmain.dartにimportします。

import 'package:cached_network_image/cached_network_image.dart';

また、main.dartの最下部に以下のクラスを追加します。このクラスではFuture<String>を指定して、そこで受け取る文字列を画像のURLとしてCachedNetworkImageに渡すFutureBuilderとして機能します。

~~~~
class NetworkImageBuilder extends FutureBuilder {
  NetworkImageBuilder(Future<String> item)
  : item = item,
  super(
    future: item,
    builder: (context, snapshot) {
      if(snapshot.hasData) {
        return CachedNetworkImage(
          imageUrl: snapshot.data,
          placeholder: (context, url) => CircularProgressIndicator(),
          errorWidget: (context, url, error) => Icon(Icons.error),
        );
      } else {
        return CircularProgressIndicator();
      }
    },
  );
  final Future<String> item;
}

上記クラスをListTile内で以下のように利用します。

ListTile(
  leading: NetworkImageBuilder(firebase_storage.FirebaseStorage.instance.ref().child(e.get('image')).getDownloadURL()),
  title: Text("${e.get('name')}"),
  subtitle: Text("${e.get('price')}円"),
)

ここでStorageから画像を取得するURLをNetworkImageBuilderに指定しています。firebase_storage.FirebaseStorage.instance.ref()でStorageにアクセスするリファレンスを取得し、child(e.get('image'))で該当のファイルを指定、getDownloadURL()でファイルにアクセスするURLを取得しています。このときgetDownloadURL()Future<String>を返却するため、一旦FutureBuilderでURLを待ち、その後CachedNetworkImageで画像の取得を待つ、という流れが必要となります。

以上の編集によって以下のようなリストが確認できると思います。これでStorageから画像を取得することができました。

以上、三回に渡ってFlutterによるアプリ開発を記述してきました。

導入編ではFlutterのSDKを用意しアプリ画面が表示されるまで説明しました。

ウィジェットレイアウト編ではアプリらしいレイアウトを作るための方法と、HTTPを通してサーバからデータを取得する方法を説明しました。

そして今回はFlutterと相性の良いFirebaseとの連携について、FirestoreとStorageを用いて説明しました。FirebaseについてはAuthenticationを導入してユーザ認証の実装をおすすめします。

ここまで記述してきた情報によって様々なアプリ開発が可能かと思います。是非アプリ開発を行ってみてください。

References

References
1 e)=>ListTile( title: Text("${e.get('name')}"), subtitle: Text("${e.get('price')}円"),

open-jtalk で日本語の読み上げをさせる

0

やること

PCに日本語テキストを音読させてみます。
mac と fodora33 で試したので
インストールのコマンドと簡単なスクリプトを記載します。

mac版

環境

uname -a
Darwin macbook1010390.local 19.6.0 Darwin Kernel Version 19.6.0: Thu Oct 29 22:56:45 PDT 2020; root:xnu-6153.141.2.2~1/RELEASE_X86_64 x86_64

brew --version
Homebrew 2.7.5

afplay -h
    Audio File Play
    Version: 2.0

インストール

brew install open-jtalk

バージョンやファイルパスなど表示されるので確認します。

以上、あとはスクリプトを書いて実行するだけです。Homebrew ありがたや。

スクリプト

cat ~/bin/mei 
#!/bin/bash

OJT_DIC=/usr/local/Cellar/open-jtalk/1.11/dic
OJT_VOICE=/usr/local/Cellar/open-jtalk/1.11/voice/mei/mei_normal.htsvoice
OJT_TMP=/tmp/out.wav
if [ -p /dev/stdin ]; then
    cat -
else
    echo $@
fi | open_jtalk -x $OJT_DIC -m $OJT_VOICE -ow $OJT_TMP
afplay $OJT_TMP

実行例

chmod u+x ~/bin/mei
mei 厳密に言うとトマトは果物です。
mei その家には人間と豚と犬と鶏と家鴨が住んでいたが、まったく、住む建物も各々の食物も殆ど変っていやしない。

fedora33版

環境

uname -a
Linux kiwi.kadosawa6 5.10.11-200.fc33.x86_64 #1 SMP Wed Jan 27 20:21:22 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

ffmpeg --version
ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers

インストール

# いろいろ取ってくるので適当なアーカイブ置き場へ移動します。
cd /usr/local/src
# 音声作成エンジンをインストールします。
 wget https://downloads.sourceforge.net/project/hts-engine/hts_engine%20API/hts_engine_API-1.10/hts_engine_API-1.10.tar.gz
 tar zxvf hts_engine_API-1.10.tar.gz
 cd hts_engine_API-1.10/
 make
 make install
# open-jtalk本体をインストールします。
cd /usr/local/src
wget https://downloads.sourceforge.net/project/open-jtalk/Open%20JTalk/open_jtalk-1.11/open_jtalk-1.11.tar.gz
tar zxvf open_jtalk-1.11.tar.gz
cd open_jtalk-1.11/
./configure --with-charset=UTF-8
make
make install
# 音響モデルをインストールします。
cd /usr/local/src
wget http://sourceforge.net/projects/mmdagent/files/MMDAgent_Example/MMDAgent_Example-1.8/MMDAgent_Example-1.8.zip
unzip MMDAgent_Example-1.8.zip
# 呼び出し易いようにシンボリックリンクを作成しておきます。
cd /usr/local/share/
ln -s /usr/local/src/MMDAgent_Example-1.8/Voice hts_voice

スクリプト

cat ~/bin/mei
#!/bin/bash

OJT_DIC=/usr/local/src/open_jtalk-1.11/mecab-naist-jdic
OJT_VOICE=/usr/local/share/hts_voice/mei/mei_normal.htsvoice
OJT_TMP=/dev/shm/out.wav
if [ -p /dev/stdin ]; then
    cat -
else
    echo $@
fi | open_jtalk -x $OJT_DIC -m $OJT_VOICE -ow $OJT_TMP
aplay $OJT_TMP

実行例

chmod u+x ~/bin/mei
mei 季も桃も桃のうち
mei 裏庭には二羽鶏がいる

所感

目が疲れているとき、こういうのを使ってドキュメントなどを確認するのも良いかもと思って試してみました。読み方の選び方やイントネーションをカスタマイズできないかなぁと思うこともありますが、未来を感じつつ現実に直面している感じがして楽しいです。

【2021年度版】GDPR/CCPA対策!Googleアナリティクスのプライバシー保護最新情報

0

デジタルビジネス部コンサルタントの関です。

主にGoogleアナリティクスを用いたデータ解析基盤構築を支援しております。近年、欧州をはじめとした地域でプライバシー保護がトレンドとなり、国内の顧客でも海外展開されていらっしゃる企業では「GDPRはどうか、CCPAはどうか」と話を伺うことが多くなりました。

もちろんGoogleさんも活発に仕組みづくりを働きかけておりますので、今回はGoogleアナリティクスを取り上げてGDPR/CCPAに対する取り組みとそのために設定すべきポイントをご紹介させていただきます。

GDPRとは

皆さんご存じかと思いますが、GDPRとは欧州で2018年6月に施行された法律「General Data Protection Regulation」の略で、日本では「EU一般データ保護規則」と呼ばれることもあります。

生活者の個人データを自分自身でコントロールできるようにするために、Cookieなどの個人情報を取得する際は「暗黙的ではない同意」を得ることが求められるようになりました。最近Webサイトを見ると、「Cookie取得を同意していただけませんか?」とポップアップが出てくることがありますよね。あれがまさにGDPRを意識した対策の一環となります。

違反した企業に対しては罰金制裁の事例もあり、Googleフランスではターゲティング広告の透明性や説明責任の欠如ということで約62億円の罰金が科せられたことは記憶に新しいかもしれません。

CCPAとは

2020年1月施行と真新しい話となりますが、米国カリフォルニア州で施行された法律「California Consumer Privacy Act」についても取り上げていきましょう。

GDPRに比べて消費者の知る権利に比重を置いており、「私の情報がどう使われているか教えてほしい」と求められたときに開示が義務化されるということが重要な部分となります。つまり、消費者から預かった情報は適切に「管理」「運用」してくださいねという法律です。

最近では、米国全土への波及、連邦法への統一が求められているなど盛んになっており、主要ブラウザがこぞってCookie制御の動きを示しています。SafariのITP対応しかり、ChromeもCookieを取得やめるかもという話が出てましたね。

Googleアナリティクスは安全か?

GDPRおよびCCPAの文脈から見た時に、Googleアナリティクスで取得された情報の管理体制には問題がないのか、というのが気になるポイントです。結論から申し上げると、サイト運営者がしっかりと仕様理解して必要な対策ができれば現行法では問題ない、と考えられます。

理解しておくべき仕様①:データ設定管理

Googleアナリティクスではデータの収集・保持・共有に関する設定をある程度調整することができます。

前提として、Googleアナリティクスなどのアクセス解析ツールでデータ取得を行う際には、サイトポリシーやプライバシーポリシーにその旨を記載する必要があります。ただ、企業によっては法的リスクなどの理由でポリシーを厳密に指定する必要があるため、その設定をツール側で調整できるのはGoogleアナリティクスの利点と言えるでしょう。

具体的にできることとして、以下の項目があります。詳細についてはそれぞれの記事で紹介予定となりますので更新をお待ちください。

  • データ処理規約に同意するか否かの選択
  • WebプロパティのIPアドレス匿名化
  • データ収集を一部またはすべて無効化
  • データ保持期間の設定
  • Googleと共有するデータの指定
  • Googleシグナルの設定確認

理解しておくべき仕様②:データ連携管理

Googleアナリティクスの特徴のひとつに、Googleエコシステム上の他ツールとの連携がしやすいという面があります。

その中でもGoogle広告のパーソナライズは、マーケティングを行う上で欠かせない機能となっていますが、ここにもGDPR/CCPAのリスクが存在いたします。最近になって、このパーソナライズの範囲を細かく管理できるようになりました。

これまでもプロパティ単位でGoogle広告との連携有無は指定できたのですが、地域単位(基本は国、アメリカは州別)でオンオフができるようになったのは明らかにGDPR/CCPAを意識した改修といえますね。

また、ユニバーサルアナリティクス(UA、従来のGAプロパティ)はもちろんのこと、GA4プロパティにおいてもイベントやユーザープロパティ単位で広告パーソナライズを管理することができます。例えばCookie同意を拒否するユーザーに対して広告パーソナライズを除外するといった設定を行うこともでき、法的リスクを回避できるのは大きいですね。

理解しておくべき仕様③:データ削除管理

さて、CCPAで求められているプライバシーの権利には「削除権」というものがございます。「Googleアナリティクスで個人情報を取得してしまった!簡単に削除できないだろうし、どうしよう…。」と枕を高くして寝られない日々を送るサイト運営者もいたかもしれません。

Googleアナリティクスで収集されたデータは、無償版の場合Googleに所属し、有償版の場合企業に所属するというルールがありますが、不適切なデータ収集をしてしまったときの対処方法としてサーバーからデータ削除するためのリクエスト機能が備わっています。

具体的な方法としては主に3つ。詳細については別記事で順次更新を予定しています。

  • プロパティごと削除する
  • 特定期間データの削除をリクエスト ※UAのみ
  • 特定ユーザーデータの削除 ※UA/GA4対応

まとめ

今回はGoogleアナリティクスにおけるプライバシー保護対策を紹介させていただきました。意外とGoogleアナリティクスデータは簡単に削除できてしまうのですが、反面ミスって消すと貴重な資源の損失につながりうるので注意も必要ですね。

とはいえ、プライバシー保護のためには事前承諾が重要です。Cookie同意ツールを利用したり、法律とGoogleアナリティクスの仕様を理解することでリスクヘッジを取りましょう。

アピリッツでは、Googleアナリティクスを用いたデータ基盤構築サービスをご提供しています。本記事の内容に限らず、困ったことや相談したいことがございましたらお気軽にお問い合わせください。

「DX時代にデジタル領域のユーザー体験設計を提供する」デジタルエクスペリエンス部 長谷 亘 × デジタルビジネス部 飯場俊耶 対談

0

アピリッツは企業のDX(デジタルトランスフォーメーション)推進を今後さらに支援するために、2/1に新組織編成を行いました。今回あらたに立ち上げたデジタルエクスペリエンス部を率いる長谷が、Webコンサルティングの現場で感じたDXの課題についてデジタルビジネス部の飯場と話します。(2021年1月取材)

業務プロセスの改善から顧客体験の創造まで

―― はじめに、アピリッツのDX推進における活動内容を教えてください

長谷:アピリッツでは以前からお客様のDX推進を助けるために様々なアプローチを取っています。

具体的には、お客様のビジネス構想の具現化に向けたデジタル技術やマーケティングのコンサルティングを生業にしている「デジタルビジネス部」を2018年より推進してきました。

また、去年の動きでいいますと、オンプレミス環境からAWSやGCPといったクラウド環境への移行を通して、お客様を支援する「クラウドインテグレーション部」を2020年に新設しています。(関連:マイグレーション後もDX推進のお付き合いを。クラウドインテグレーション部設立記念、西脇学 × 剣持大介 対談

そして次はということで、DX推進でも重要となる顧客体験の領域でも事業に力を入れようと考え、組織編制ラッシュではありますが、あらたに「デジタルエクスペリエンス部」を立ち上げました。ユーザーに触れるフロント側の体験向上をテーマに、DX推進およびデジタル人材を育成していくためのトリガーとなります。

―― DXという言葉をよく耳にするようになりました。飯場さんは、コンサルタントとしてアピリッツのお客様との対話を重ねていますが、お客様のDXへの関心度や進み具合はいかがでしょうか?

飯場:多くのお客様がDXを経営の目標に掲げていらっしゃいます。ですが「何をすれば?」というところで止まっている印象ですね。せっかく実店舗でよいサービスや商品を提供しても、それをどうシステム化・デジタル化するか? といったところが各業界共通の課題であると感じています。

たとえば、数千点の商品をただズラッと紙のカタログのように並べただけのECでは、ユーザーは何を買えばいいかわからないので売れません。実店舗で提供するサービス・商品が持つ良さとオリジナリティが、デジタルにフルで活かしきれていないのが現状だと考えています。

長谷:IT化でも頭を悩ませているのにDX化が来ててんやわんやなイメージはあるね。大変です。

競争も激化していく中でそれぞれの企業努力でサービスが多様化・複雑化しているってことなのかな。そして、デジタル領域において、ユーザーがわかりやすくサービスを体験する仕組みや表現が難しいと。

飯場:そうですね、その業界でトップを取るための戦略として、顧客に寄り添ったサービス・商品を作っていらっしゃいますが、それをデジタルでどうつくり上げるかに頭を悩ませています。

デジタル領域でも「また使いたい」をつくる

―― サービスが複雑化するとどういうことがおこるのでしょうか?

長谷:すごく単純な話なんですが、そのユーザーにとって良いサービスのはずなのに気づけないということが起きてしまいます。せっかくの素晴らしいサービスなのに伝わらないって悲しいですよね。

ですので、複雑でも自然とファンになってくれるわかりやすさや伝え方の仕組みが求められています。「顧客」となってくれるファンをいかに増やしていくかを徹底的に分解して再現していくわけです。

―― 売上数値を伸ばす従来のマーケティングとの違いはあるのでしょうか?

長谷:定義が難しくて、どっちもビジネス成長といった目的は同じです。ただ「数値」を満たすか、「顧客満足度」を満たすかといったアプローチに違いがあります。

今までは、ビジネス上の具体的な数値を作るためのマーケティングや、デジタル技術によって業務を効率化していくことが注目されてきました。売上やコスト最適化といった感じです。

これからも必要なアプローチ方法です。ですが、コロナ禍といった世の中の常態が変わる出来事は今後も起こりますし、目の前の数値を追うだけでは業界で生き残れないと、お客様も不安に思っています。

その中で、サービスと顧客との間に信頼関係を築き、「長くファンになってくれる顧客」を作ることが大事で、何度も何度もサービスを通して「良かったな」と思う体験を増やすような「顧客主義」の考え方を私たちはプロジェクトに取り込んでいます。

―― なるほど。体験を良くするアプローチを担うのがデジタルエクスペリエンス部なわけですね。

飯場:そうですね。「デジタル領域のビジネス構想と戦略の立案や、数字計画を立てる」のがデジタルビジネス部の役割。

そして、ユーザーにその戦略をどのように届けるのかといった「デジタル領域でのタッチポイントを設計する、良い体験を創る」のがデジタルエクスペリエンス部の役割かなと。

長谷:まさに、そんな感じですね。同じような名前の部署名でややこしいですが(笑)

ただ、完全に分ける必要はないです。お互い重なるところも実際は多く、「数字と顧客体験の向上」を行き来しながらサービスを提供していくイメージです。

誰が、どこで、どのような場面で、何に興味をもって、気が付いたら習慣になって、良いなと思ってもらう、といった体験全体を設計し、定量的なデータも参考に作っちゃうというのが勝利の方程式です。

もともと、アピリッツは10年以上前からマーケティングやデザインのサービスを提供していますし、デジタル技術やエンジニアのサービスも提供していく中で、顧客主義のニーズが潜んでいることはキャッチしていました。

近年は特にDX推進や経産省のDXレポートでも「ユーザーエクスペリエンスが重要である」「作ったサービスを使ってもらわないと意味がない」ことが述べられています。

これらの経緯をふまえ、デジタル領域でユーザー体験を作ることに特化したチームが必要でした。それが「デジタルエクスペリエンス部」です。

ユーザー体験つくりは顧客とデジタルをつなげる伴走力

―― アピリッツがユーザー体験を考えて実現できる理由を教えて下さい。

長谷:ユーザー体験の向上に必要な実行プランを社内で完結して持っているワンストップソリューションの体制ですかね。

ユーザー体験を実現するうえでは、総合的なアプローチが必要で、学問をまんべんなく修めないとどこかで穴が空いてしまう。周辺サービスに穴が空いてしまうと、顧客に的確に届きにくくなる。アピリッツはその穴を埋めることができる会社です。

飯場:それは現場でも強く感じています。デザイン制作、システム開発、マーケティングといった知識に加えてお客様の業界知識、お客様のユーザーはどういった人たちなのか?、お客様の競合他社はどこで、そこと差別化できるのはどういう点か?などの観点を凝縮してデジタルを作っていけるなと。

長谷:長くアピリッツにいるので慣れてしまっていますが、ビジネス構想とかフロント側の設計について社内の開発陣に断られることってほとんどなくて、シンプルにすごいなといつも思います。同じ会社で一気通貫で作ることの強さや心強いメンバーがいるって素晴らしいです。

―― ユーザー体験について大事にしていることはどのようなことでしょうか。

長谷:当たり前の話かもしれませんが、その業界やサービス、顧客の特性を知ることが大事だと思っています。

その際に、複雑化したビジネスをお客様に教えていただくことも大切です。ユーザー体験を「お客様の情報」と「デジタルな実行」で伴走してつなげていく感じです。難しいのですが、だからこそ価値があるわけですし、やりがいがあります。

飯場:お客様のメンバーへの理解も大事ですよね。私達からのご提案は、技術や顧客体験と同じくらいお客様の社内にいるメンバーの仕事上の体験にも影響が及びます。ですから、5年後10年後にどこを重要視するか、そういった理念を対話によって汲み取り、それを貫きます。

3,000の企業があれば3,000のセカイがある

―― お客様の顧客も、お客様自身の未来も大事にする。そのための対話が重要であると。

飯場:何度も重ねます。プロジェクトは対話のなかで出てきたものを実現する手段なのです。もちろんプロジェクトが始まったあとも対話は継続します。

そうすることで新しい領域を開拓できると信じていますし、ちょっとした悩みもご相談いただけるようになることが寄り添うことの結果だと思います。

たとえば5年間で数億円かけるプロジェクトの場合、5年間も一緒にお付き合いがあるわけですから、ゼロベースで関係を構築するのは双方ともに怖いものです。そのため、日頃からお客様の持っているサービスや理念を知ること、ビジョンやミッションから新しいサービスを提案します。

長谷:今まで培ってきた情報や知識を総動員しないとできない仕事ですよね。特にお客様のサービスが世界で愛されるためには、お客様の理念を我々が先に愛していくというのが大事。

飯場:アピリッツのミッションである「セカイに愛されるインターネットサービスをつくり続ける」と重なりますね。3,000の企業があれば3,000のセカイがあって良いと思っています。

長谷:それ、いい言葉だね。お客様がイメージするセカイについて私達が色を付けることに賛同して、具現化していくような仕事。ってなんだかかっこつけた感じになっちゃいましたが(笑)

飯場:でも、ミッションってかっこいいほうがいいですよね(笑)

―― 最後にDX推進への抱負をお願いします。

長谷:お客様のサービスをいかにデジタルで実現するか、企業価値を上げてゆくかといったDXの構想は、お客様ご自身だけで描くのは難しいですし、私たちだけでも厳しい。だからこそ、アピリッツがお客様と共に伴走し、様々な意見を出しあうことでつくりあげることができると思っています。

インターネットの時代がまた変わろうとしている稀有なこの瞬間を、お客さんと社内のメンバーと楽しんで進めて共に成長できるような企業でありたいです。がんばります。

―― 長谷さんと飯場さんの顧客への情熱が伝わってきました。ありがとうございました!

バンディットアルゴリズムで複数案を効率的に評価!

0

はじめに

データイノベーション部の浅田です。

文章を書くときに、何度も構成や表現を練り直すことを推敲といったりします。この推敲という言葉は中国の故事に由来します。

唐代の賈島という詩人が詩を作っていた際に、「僧は推す月下の門」という句を考えつきますが、「推す」という表現を「敲く」という表現としたほうがいいのではないか、と迷い始めます。彼は考えに夢中になってるうち、韓愈というお偉いさんの行列に突っ込んでしまい咎められますが、韓愈が漢詩の大家だったので、「”敲く”のほうがいい」とアドバイスをもらうなど詩についておおいに語り合った、というのがこの故事の顛末です。

アイデア評価手法としてのA/Bテスト

詩を書くことはないにしても、ビジネスにおいても複数のアイデアを比較・評価するということはよくあります。

前述の賈島の例では、自分のセンスであったり、大家の意見を頼りにアイデアを評価したわけですが、統計学の力を借りてアイデアを評価することもできます。

例えば、Webサービスなどのデザインの比較・評価でよく利用される手法にA/Bテストというものがあります。これはA案とB案という二つのデザイン案があったとして、ユーザをランダムにA案、B案に振り分けて、そのデザイン案に対する反応を比較し、その結果どっちかの案が優れていると統計的に実証できれば、その案を全面的に採用する、というものです。

それをどう評価するかですが、二つの案を望ましい結果(たとえばクリック行動)を確率的に生み出すモデルとみなします。多数のユーザに対してランダムに提示して、その反応結果をデータとして集めることで、それぞれの案が望ましい結果を生み出す確率を推定し比較します。

どれぐらいデータを集めればいいのか

確率モデルのパラメータを推定するにあたって、一番確実なのはとにかくデータを集めることです。データを集めれば集めるほと、より正確なパラメータ、つまり望ましい結果を生み出す確率を推定することができます。

では、どれぐらいデータを集めればいいのでしょうか。100件?1000件?残念ながら、明確にこれだけあれば大丈夫という基準はありません。明らかに確率が違うなら100件でも十分なケースもあるでしょうし、どちらも甲乙つけがたいケースでは10000件でも十分ではないかもしれません。

問題になるのは件数だけではありません。データをたくさん集めればいいのは間違いないですが、データをたくさん集める、つまり長期間テストを実施するということは、ある一定のユーザには劣る案を提示し続けるということになります。例えば二つの案のうち、A案が改善案、B案が現状維持案であるとして、A案がより優れた案であったならばトータルとしてはB案だけでやっていた場合よりも良い結果になる可能性があるので、それほど問題にならないかもしれません。ただ、A案が実際には劣っている案だったとしたら、トータルの結果としては悪くなる可能性があります。つまり、続ければ続けるほど、損失が生まれる可能性があります。

多腕バンディット問題

多腕の画像

そこで、複数の案を試す際に、なるべく損失を少ないように試すアルゴリズムとして、バンディットアルゴリズムというものがあります。

バンディットとは、ギャンブラーから金を奪い取る様子から盗賊に連想された「スロットマシン」の俗称です。複数のあたりの確率が異なるバンディット(スロットマシン)が存在する際に、どのように複数のアーム(レバー)を引けば得られる総額を最大化できるか、という問題を多腕バンディット問題と呼び、そのためのアルゴリズムがバンディットアルゴリズムになります。なので、多腕バンディットといっても、盗賊に腕がたくさん生えているわけではありません。

バンディットアルゴリズムの概念

バンディットアルゴリズムをイメージしやすくするために、こんな設定を考えてみましょう。

あなたは魔王を倒しにいく戦士です。魔王を倒すための武器を手に入れるため、武器屋に行きました。武器屋の主人に「この店で一番良い剣を買いたい」と伝えると、三つの剣を提示されました。武器屋の主人曰く「この三つの剣はどれも最強クラスの切れ味なんだが、時々しかその切れ味を発揮しない魔剣なんだ。切れ味を発揮すれば鉄だって簡単に切れる」ということです。

予算の都合上、三つの剣を全部買うことはできないので、切れ味を発揮する確率が一番高い剣を選ぶ必要があります。そこであなたは武器屋の主人にこう持ち掛けます。

「一回ごとに多少の料金を支払うから、それぞれの剣で試し切りをさせてほしい」

武器屋の主人は言いました。

「わかった。鉄を切れたら(切れ味を発揮できたら)、祝儀としてその回の試し切りの料金はタダでいい」

さて、この時に「切れ味を一番発揮しやすい剣をあまりお金をかけずに選び出すための戦略」というのがバンディットアルゴリズムとなります。

ε-greedy(イプシロングリーディ)アルゴリズム

バンディットアルゴリズムの筆頭格が、このε-greedyです。εはギリシャ文字でイプシロンと読みます。ここではεはある一定の小さい確率を意味します。

ε-greedyにおいては、

  • εの確率でランダムに案を選びます。
  • (1-ε)の確率で、それまでに得られたデータの平均値が最も高い案を選びます。

例えば先ほどの剣の例で説明すると、例えば10%の確率でランダムに剣を選んで試し切りを行います。そして、90%の確率でそれまでに一番鉄を切れた確率の高い剣を選んで試し切りを行います。

つまり、基本的には今まで試したなかで一番有望そうな案を試すけれども、一定確率において、別の案もランダムに試してみる、という戦略になります。

複数の案の中で優れた確率を持つ案があるのであれば、その案が大部分で選択されるように収束されるアルゴリズムです。

一方で、小さい確率とはいえ、ある一定確率で見込みがない案を最初から最後まで平等に試行してしまうアルゴリズムでもあります。

例えば、3回試した際に1回しか鉄を切れなかった剣Aと3回試した際に3回とも鉄を切れた剣Bがあった場合に、剣Aのほうはたまたま運が悪く、剣Bのほうはたまたま運が良かった可能性はあるので剣Aもまだ試す価値はありそうですが、もしこれが剣Aが100回中10回と剣Cが100回中50回という結果であれば、剣Aが剣Cよりも優れている可能性はあまりなさそうだと直感的に思うのではないでしょうか。

そのような時にもε-greedyは、平等に剣A, 剣B, 剣Cをランダムに選んでしまうので、結果が収束するのに時間がかかりますし、一定確率であまり見込みのない案を選んでしまいます。

トンプソンサンプリング

ε-greedyの問題点の一つは、複数の案を試す際にすべての案を常に平等に試そうとする点にあります。この問題点を改善するために、ベイズ統計の仕組みを利用したアルゴリズムがトンプソンサンプリングです。

ベイズ統計学についてはベイズ統計学の世界への誘いで記載したように、その特徴の一つとして確率モデルのパラメータを確率分布で表現します。

トンプソンサンプリングでは以下のような手順を踏みます。

  1. 各案の確率モデルのパラメータを確率分布で表現します。
  2. それぞれの確率分布から乱数を生成(サンプリング)します。
  3. サンプリング結果のうち一番よい乱数を生成した確率分布をもつ案を次に試す案として採用します。
  4. 得られた結果を使って、その案の確率分布をベイズ更新して事後分布を計算し、その案の新たな確率分布とします。
  5. 2~4を繰り返します。

前述の記事において述べていますが、何回中何回成功したというデータを観測することにより、その成功確率をベータ分布という確率分布として表すことができます。

剣の例で言えば、各剣ごとに試行回数のうち何回鉄を切れたかのデータを観測することによって、鉄を切れる確率をベータ分布として表現できます。

確率分布が定義できれば、乱数をサンプリングすることができます。ミソとなるのは、期待値よりも大きい値がたまたま得られることも、期待値よりも小さい値がたまたま得られることもあり得ますが、確率的にあまりあり得ない値はサンプリングされにくいということです。

なので、「採用される案が偏る」という状態が発生するのは、それぞれの確率分布の期待値において統計的に有意差があるということでもあります。

このようにトンプソンサンプリングは、統計的に有望な案を効率的に試しつつ、損失を抑えるアルゴリズムとなっています。

コード例を挙げておきます。

from matplotlib import pyplot as plt 
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as st


class Sword:
    def __init__(self, p):
        self.p = p
        self.a = 0
        self.b = 0

    def slash_count(self):
        return self.a + self.b
        
    def slash(self):
        result = np.random.random() < self.p
        if result:
            self.a += 1
        else:
            self.b += 1
        return result
            
    def beta(self, x):
        return st.beta.pdf(x, a=self.a + 1, b=self.b + 1)
    
    def sampling(self):
        return np.random.beta(self.a + 1, self.b + 1)

    
class ThompsonSampling():
    def __init__(self, swords):
        self.swords = swords

    def _next_sword(self):
        samples = [sword.sampling() for sword in self.swords]
        return samples.index(max(samples))

    def do(self, counts):
        for _ in range(counts):
            self.swords[self._next_sword()].slash()


swordA = Sword(0.8)
swordB = Sword(0.5)
swordC = Sword(0.3)
swords = [swordA, swordB, swordC]

ThompsonSampling(swords).do(1000)

theta = np.arange(0, 1.01, 0.01)
plt.plot(theta, swordA.beta(theta), label="swordA")
plt.plot(theta, swordB.beta(theta), label="swordB")
plt.plot(theta, swordC.beta(theta), label="swordC")
plt.legend(bbox_to_anchor=(0, 1), loc='upper left', borderaxespad=1, fontsize=10)

# それぞれの剣を振った数
for sword in swords:
    print("振った数:{}, 鉄を切れた数: {}".format(sword.slash_count(), sword.a))

可視化で表示されたグラフは以下のようなものです。

また、参考までに剣を振った数と鉄を切れた数は

剣A 振った数:77, 鉄を切れた数: 58  
剣B 振った数:14, 鉄を切れた数: 6  
剣C 振った数:9, 鉄を切れた数: 3

となっています。

一番確率の高い剣Aを一番多く試せていることがわかります。

試しに試行回数を1000回にした場合には

剣A 振った数:974, 鉄を切れた数: 780
剣B 振った数:17, 鉄を切れた数: 7
剣C 振った数:9, 鉄を切れた数: 3

となりました。有望案である剣Aの回数は増えている一方、それ以外の案の試行回数はほとんど増えていません。

終わりに

さて、トンプソンサンプリングのアルゴリズムによって、あなたは予算内に一番切れ味を発揮できた剣を選びだすことに成功し、感嘆の声をあげます。

念願の魔剣を手に入れたぞ!

この後どうなったかはご想像にお任せしますが、このようにバンディットアルゴリズムを使うことで、複数のアイデアを効率的に評価することが可能になります。ちなみに、バンディットアルゴリズムは強化学習において最適な方策を選択するためのアルゴリズムとしても使用されます。

なお、剣の例におけるトンプソンサンプリングでは、ほぼ一番有望な剣が選択されるように収束していますが、一番有望な剣でも鉄を切るのに失敗するケースが一定数存在します。なので、何も考えずにランダムに選択するケースや、ε-greedyに比べれば損失を少なくできていますが、さらに損失を少なくするためには、試行回数が十分であると判断した段階で打ち切る必要があります。試行回数が十分かどうかを判断するのはバンディットアルゴリズムの範疇を超えますが、一案としては、各案ごとの期待値に対して仮説検定を行って判断するといったことを行っても良いかと思います。仮説検定に関しては、またの機会にご紹介できればと思います。

以上、この記事が皆様の意思決定の一助にでもなれば幸いです。

Flutterによるアプリ開発 <ウィジェットレイアウト編>

0

ゲームデザイン部エンジニア中村です。リモートワーク中は昼飯自炊勢です。

前回はFlutterによるアプリ開発<導入編>をお送りしました。今回はFlutterのウィジェットを実際に並べていき、アプリらしい画面を整えていきましょう。

そのためには、Flutterの深層までの理解は必要ありません。この記事ではレイアウトを作成するための知識だけを提供します。一部のソースコードについてはおまじないと思っていただければ問題ありません。エンジニア初心者やデザイナの方でもコピー&ペーストするだけでレイアウトが作れるようにしてきます。

ウィジェットレイアウトの基本

初期生成ファイルの理解

まずはプロジェクト生成時に自動で作られたファイルの内容をおおよそ理解しましょう。

ここでは自動生成のコメントをすべて削除した状態にしています。また、ここで編集するファイルはlib/main.dartのみです。その中でどのようにウィジェットを指定し、テキストやボタンを表示しているのか見ていきましょう。

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

このブロックでまず注目すべきはprimarySwatch: Colors.blueです。これはFlutterに事前に用意されたテーマカラーを指定することでヘッダやボタンなどの基本色を指定することができます。Colors.greenColors.cyanなどが用意されています。

また、MyHomePage(title: 'Flutter Demo Home Page')の箇所ではヘッダに表示するタイトルを指定しています。ここも自由に指定すると良いでしょう。

上記2箇所について、今回は以下のように編集しました。

~~
primarySwatch: Colors.green,
~~
home: MyHomePage(title: 'Dashboard')

続いて、ウィジェットのレイアウトをしている箇所です。

Scaffold(
  appBar: AppBar(
    title: Text(widget.title),
  ),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          '右下のボタンをクリック',
        ),
        Text(
          '$_counter',
          style: Theme.of(context).textTheme.headline4,
        ),
      ],
    ),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: _incrementCounter,
    tooltip: 'Increment',
    child: Icon(Icons.add),
  ),
);

Scaffoldは工事などに利用する「足場」という意味で、足場を組んでから内部の部品を組み立てていくというイメージです。Flutter/Dartによるコードの構造として、ウィジェット名()としたときの()の中に更にウィジェットが記述される形になっています。

Centerについてはchild:に対してウィジェットを指定するため、これがそのまま親子関係になります。Columnは複数の子要素を持つことからchildren:に対してウィジェットの配列を指定します。

FloatingActionButtonは右下に表示されているボタンです。これはScafoldに対して1つだけ指定することができるウィジェットであり、ColumnCenterなどの子要素になることはありません。

ハンズオンでレイアウトする

CenterとColumnの基本レイアウト構造

それではソースコードを簡単に編集していきましょう。まずは見やすくするためにScafoldの内部をCenterとその中のTextだけにします。

Scaffold(
  body: Center(
    child: Text(
      'これはテストです',
    ),
  ),
);

ヘッダもフローティングボタンもなくなり、中央にテキストが表示されるだけとなりました。これにより、Center子要素を中央に表示するウィジェットであるとわかると思います。

続いて、CenterColumnに書き換え、Textを3つに増やしましょう。このとき、Columnchildではなくchildrenの指定となります。

Scaffold(
  body: Column(
        children: <Widget> [
          Text('これはテストです'),
          Text('これはテストです'),
          Text('これはテストです'),
        ]
      )
  ),
);

左上にテキストが3つ並ぶ形となりました。Columnchildrenに指定された子要素を縦に並べるウィジェットです。現状では中央に寄せる設定をしていないためこのような表示になります。

ここでColumn内部を以下のように書き換えましょう。重要なのはmainAxisAlignmentcrossAxisAlignmentです。

Scaffold(
  body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: <Widget> [
          Text('これはテストです'),
          Text('これはテストですテストです'),
          Text('これはテストですテストですテストです'),
        ]
      )
  ),
);

テキストが中央に表示され、長さの違うテキストは右寄せになっています。これがmainAxisAlignmentcrossAxisAlignmentの効果です。以下の画像にその効果を図示します。

緑の矩形がColumn自身を表します。縦方向には親要素を満たすようになりますが、横方向には子要素の最大幅に合わせます。

この中でMainAxisとは、Columnの場合子要素を積み重ねる縦方向の意味になります。つまり、MainAxisAlignment.centerとすることで青い矩形で示した子要素のまとまりを縦方向に対して中央に配置することができます。

そして、CrossAxisはそれに直交する方向となるため赤い矩形で示した子要素自体がそれぞれ横方向に整列することになります。今回はそれぞれのテキストの長さが異なり、CrossAxisAlignment.endとしたことから最も横幅が長い子要素に合わせて右揃えとなっています。同様に、startとすれば左揃え、centerとすれば中央揃えを表現できます。

Columnは縦に積み重ねるウィジェットですが、横に並べるウィジェットとしてRowも存在します。Rowの場合には要素を横並びにするため、MainAxisは横方向となり、CrossAxisは縦方向となります。ColumnRowはレイアウトを作成する上で頻出ウィジェットですのでMainAxisCrossAxisを覚えておきましょう。

リストを表示する

SNSやショッピングアプリなどではリストビューがよく使われていると思います。Flutterではそういったリストを表示するためのウィジェットが用意されています。以下のようにコードを書き換えてみましょう。

Scaffold(
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: ListView(
      children: [
        ListTile(
          leading: Icon(Icons.person),
          title: Text("人物アイコン"),
          onTap: () {},
        ),
        ListTile(
          leading: Icon(Icons.mail),
          title: Text("メールアイコン"),
          onTap: () {},
        ),
        ListTile(
          leading: Icon(Icons.map),
          title: Text("地図アイコン"),
          onTap: () {},
        )
      ],
    ),
  )
);

ListViewウィジェットのchildrenに対して子要素を指定するとそれだけでリストを表示することができます。このときListTileウィジェットを利用すると、アイコンとテキストの組み合わせというよく見るリストを作ることができます。onTapを指定することでそれぞれのリスト項目をタッチした際の処理も追加できます。

また、ListViewの親要素となっているPaddingウィジェットはCSSなどでも見られるpaddingを意味し、レイアウトでは頻繁に使われるため覚えておきましょう。

続いて、同様のリスト表示であるグリッドビューを試します。様々なレイアウト方式で、コレクションビューやタイルビューと呼ばれるリスト表示です。以下のようにコードを編集しましょう。

Scaffold(
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: GridView.count(
      crossAxisCount: 2,
      crossAxisSpacing: 4,
      mainAxisSpacing: 4,
      children: [
        ListTile(
          leading: Icon(Icons.person),
          title: Text("人物アイコン"),
          onTap: () {},
        ),
        ListTile(
          leading: Icon(Icons.mail),
          title: Text("メールアイコン"),
          onTap: () {},
        ),
        ListTile(
          leading: Icon(Icons.map),
          title: Text("地図アイコン"),
          onTap: () {},
        )
      ],
    ),
  )
);

GridView.countでグリッドを作成し、childrenに子要素を指定します。今回はListViewと同じListTileを指定しているのでアイコンとタイトルの表示のみです。それでもグリッドビューらしく自動で矩形表示が行われます。GridView.countとしてウィジェットを指定すると、crossAxisCountに横方向に要素をいくつ並べるかを指定します。タブレットなどの大きい端末では大きい数値にすると見やすくなるでしょう。

データからリストを作る

ショッピングアプリは表示する商品情報を常にサーバから取得しなければなりません。そのためには、取得したデータからレイアウトを表示すべきです。今回の例ではリストに表示する子要素をサーバから取得し、ListTileのタイトルに反映されなければなりません。これを実現するために、まずは用意されたデータからListTileを生成してみましょう。

// 最上部2行目付近
const datas = [
  {'icon': Icons.person,'title': "人物アイコン",},
  {'icon': Icons.mail,'title': "メールアイコン",},
  {'icon': Icons.map,'title': "地図アイコン",},
  {'icon': Icons.map,'title': "地図アイコン",},
  {'icon': Icons.map,'title': "地図アイコン",},
  {'icon': Icons.play_arrow,'title': "再生ボタン",},
  {'icon': Icons.photo_sharp,'title': "写真アイコン",},
];
~~~~
Scaffold(
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: ListView(
      children: datas.map[1]e) => 
        ListTile(leading: Icon(e['icon']),
          title: Text(e['title']),
          onTap: () {},
        )
      ).toList(),
    ),
  … Continue reading.toList(),
          );
        }
      },
    ),
  )
);

上記画像のように天気の表示ができたでしょうか。HTTP通信などで時間がかかる処理を待つ場合にはFutureBuilderを使用します。これはfutureに指定した処理が終わるのを待ってウィジェットを表示することができます。

builderの中でif(!snapshot.hasData)という書き方をしていますが、これはFutureBuilderが待っている間、データの取得ができていないため代わりとなるウィジェットを表示しています。今回はCircularProgressIndicatorを指定し円形の読込中マークを表示しました。データの読み込みが完了するとその結果がsnapshot.dataに渡されますので、API結果のJSON文字列をデコードし、得られたデータからListTileウィジェットを作成しています。せっかくなので天気マークはAPIで得られる画像を利用しています。

まとめ

今回はFlutterの基本的なレイアウト構造であるCenter/Columnと、様々なアプリでよく利用されるListViewGridViewについて説明しました。さらにHTTP通信結果をレイアウトに反映する方法について記述しましたので、これだけでも簡単なSNSやチャットツールなどを作ることができるかと思います。

Flutterにはまだまだたくさんのウィジェットがありますので、やってみたいレイアウトなどがあれば公式ドキュメントのウィジェット一覧が非常に参考になるのでご一読ください。

次回はFlutterとFirebaseの連携についてまとめたいと思います。

References

References
1 e) => ListTile(leading: Icon(e['icon']), title: Text(e['title']), onTap: () {}, ) ).toList(), ), ) );

https://spirits.appirits.com/wp-content/uploads/2021/01/Simulator-Screen-Shot-iPhone-11-Pro-Max-2021-01-25-at-17.11.53-139x300.png 139w, https://spirits.appirits.com/wp-content/uploads/2021/01/Simulator-Screen-Shot-iPhone-11-Pro-Max-2021-01-25-at-17.11.53-194x420.png 194w" sizes="(max-width: 240px) 100vw, 240px" />

ソースコード上部のimport文が記載された下にデータを作成します。そしてこのデータを使うようにGridViewの中を書き換えました。GridViewchildrenに対しては以下のような処理順を行っています。

  1. datasに対してmapすることで、含まれるデータ一覧の全てに対して共通の処理を行う
  2. 各データに対してListTileを作成し、leadingtitleにそれぞれデータを指定する
  3. 最後にmapしたデータをリストに変換する。

このようにすることで与えられたデータから一覧を表示することができます。

それでは実際にサーバからデータを取得し表示してみましょう。今回は天気予報APIをお借りして東京都の天気を取得し一覧表示します。

まずはHTTP通信できるようにしなければなりません。以下のようにpubspec.yamlに1行を追加して保存しましょう。Flutterでは追加で利用するプラグインなどをこのファイルに記述します。

dependencies:
  flutter:
    sdk: flutter
  http: ^0.12.2    // ← 追加

これでhttpプラグインが利用できるようになったので、main.dart側でHTTP通信を利用するための宣言をしましょう。同時にJSON文字列をデコードするためのプラグインもimportします。

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;   // ←追加
import 'dart:convert'; // ←追加

プラグインを利用するために書き換える箇所は以上です。それでは天気予報APIから東京都の天気を取得して表示してみます。以下のような書き換えを行います。

Scaffold(
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: FutureBuilder(
      future: http.get("https://weather.tsukumijima.net/api/forecast?city=130010"),
      builder: (context, snapshot) {
        if(!snapshot.hasData) {
          return CircularProgressIndicator();
        } else {
          var list = json.decode(snapshot.data.body) as Map<String, dynamic>;
          return ListView(
            children: (list['forecasts'] as List<dynamic>).map((e)=>ListTile(
              leading: Image.network(e['image']['url']),
              title: Text("${e['dateLabel']} - ${e['telop']}"),
              subtitle: Text("${e['date']}"),
            

【Mac】いちげきひっさつショートカット Automatorで業務効率化

0

はじめに 「片手で仕事を実行したい」

2020年に入社したIです。

普段いただいている業務の一つにお客様のサイトの保守改修があります。IT分野の導入を行う企業との窓口になっているサイトであり、更に売り上げを伸ばすべく改修の依頼が飛んできます。

こちらの業務をしている時、少々困っていたことがありました。
アプリの起動に手間がかかりすぎるということです。

具体的な起動までの手順としては、以下の6つの操作が必要でした。

ターミナルの起動
プロジェクトのディレクトリに移動
重複すると起動しなくなるファイルの削除
アプリの起動
クロームで管理側画面を開く
クロームでユーザー側画面を開く

それなりに重いアプリなので起動しっぱなしというわけにもいかず、また再起動しないと反映されないものもあるため、何度もこの操作を行っていました。多い時で1日6回、週40回程になります。

いやもうめんどくさい!なんとかしてくれ!
そう思っても、なんとかできるのは自分しかいません。

スペニットやクリップボード拡張アプリを調べたのですが、ワンタッチで全ての動作を行ってくれるものを見つけられませんでした。

もう、ワンタッチで全ての動作を完了してくれるものはないのだろうか。
諦めて妥協しようとした時、MACには標準的に繰り返し作業を助けてくれる機能があることを思い出しました。
そう、Automatorです。

片手で仕事を実行する

Automatorを利用して、例の面倒な作業をワンタッチで実現するようにしました。

━━━いちげきひっさつで終わらせたい!

そう思ってできたのがこちらです。

(都合上、コマンドと動画に編集を加えてあります)

いかがでしょうか、計4回の操作をワンタッチで実現することができます。

つくりかた

(所要時間20分)

1実行環境の用意

システム環境設定を起動
セキュリティとプライバシーを選択
アクセシビリティを選択し、カギを解除し、Automatorを許可し、ターミナルを許可

コマンドを実行したいアプリを許可して下さい。今回はAutomatorに加えてターミナルを許可しました。

2Automatorに機能を作成

Automator起動
クイックアクション選択
AppleScriptを選んでここにコードを貼り付ける

コードはこちらを使用し、貼り付けたらCmd Sで好きな名前で保存して下さい。
(今回の保存時の名前はxxにしました。)

on run {input, parameters}
	
	tell application "System Events"
		keystroke "cd"
		key code 49 -- space bar
		keystroke "~/Desktop"
		keystroke return
	end tell
	
	return input
end run

3ショートカットの割り当て

キーボード設定を選択
ショートカット 、サービスと選択すると、一番下に先ほど追加した機能があり、ショートカットを追加できる

ショートカットを追加を押した後、好きなコマンドを割り当てて下さい。
(今回はCmd Alt Fにしました)

追加完了

4実行確認

ターミナルを起動して、Cmd Alt Fを押してみます。

Desktopに移動できれば完了です!

この機能を作るまで、私は面倒な例の操作を終えるまでに10秒近くかかっていました。一度操作をする度に10秒短縮できていると考えると、最初に時間を投資して作った分の時間は既に返ってきたのではないかと思っております。

似たケースがあればこちらの機能を作ってみてはいかがでしょうか。

おまけ:Automatorあるある

この機能を作ろうとしている時に詰まった部分です。検索にヒットするといいなあと思って載せています。

✅ 勝手に日本語入力になる

keystroke "abc aiu" #結果 abcあいう となります。空白で日本語に切り替わりました。

✅ 空白入力ができない

空白は日本語切り替えになってしまいます。そのため、別のコードで代用しましょう。

key code 49 -- space bar #空白入力

くぁwせd(よくわからない日本語)が入力される

コマンド実行時に日本語入力になっているとなります。

✅ 今回Automatorで追加したクイックアクションがどこに追加されているか

/Users/ユーザ名/Library/Services/xx にあります。

Flutterによるアプリ開発<導入編>

0

ゲームデザイン部エンジニアの中村です。部内プロジェクトの技術支援やエンジニアスキルアップの画策など行っています。クライアントエンジニアですがサーバ設計もインフラ構築もやります。

長いことアプリ開発に携わってきましたが、困ったことにアプリ開発には多大なコストが掛かります。

アプリ自体だけではなくサーバ実装も必要であり、ユーザ動向を解析したりインフラ監視をしたりとやることが非常に多いのです。今はゲームであればUnityで簡単に開発できますが、Android2.3/iPhone4Sの時代からアプリ開発をしていたわたしとしてはAndroidアプリのJavaとiOSアプリのObjective-Cを使い分けることが苦痛でした。

それぞれでソースコードを書き、レイアウトを作るため管理コストが嵩んでいたのです。

そんな私が最近

「Flutter?ReactNative?マルチプラットフォームで開発できる。なにそれすごい」

と一つのコードでアプリ開発ができることを知りました。

さっそく飛びついてアプリを作ったため、今回はFlutterについて3本立てでご紹介します。

  1. 導入編
  2. ウィジェットレイアウト編
  3. Firebase連携編

Flutterとは

FlutterとはGoogleが開発したアプリケーションフレームワークです。

一つのプロジェクトでAndroidとiOSのアプリを開発することができます(web対応はβ版)。このマルチプラットフォームに対応した使い勝手はUnityと同様ですが、FlutterはゲームではなくSNSやECなどのアプリの開発を目的としています。

特に、マテリアルデザインを前提とした多くのウィジェットが用意されており、それらを組み合わせるだけでスタイリッシュなアプリを開発することができます。

以下の画像はわたしが個人的に作成したパントリーストック管理アプリです。

開発のために必要なものはコードエディターとFlutterSDKのみで、基本的に用意されているGetStartedに沿って進めることができます。

コードエディターは多数のExtensionが用意されているVSCodeがおすすめです。さらにFlutterの外部ライブラリも手軽に導入できます。また、Flutterではソースコードの変更を検知するホットリロードが採用されている点が非常に強力です。

Flutter開発の基本

それではFlutterのGetStartedに沿ってSDKをインストールしていきましょう。

基本的にドキュメントは英語なので日本語で説明を加えていきます。バージョンはflutter_macos_1.22.5で進めていきます。テキストエディタはVSCodeです。

インストール

FlutterSDK

  1. 「Get the Flutter SDK」とあるのでflutter_macos_1.22.5.zipをダウンロードします
  2. 開発用のフォルダ(今回は~/development)を作成し、その中にダウンロードしたzipを移動、解凍します
  3. 解凍したflutterフォルダの中にはFlutterの実行ファイルが含まれているため、PATHを通します
export PATH="$PATH:$HOME/development/flutter/bin"

ここまででFlutterSDKのインストールができました。

さらにXCodeAndroidStudioをインストールしましょう。

ここまでインストールしたら、flutterのコマンド動作確認のためにdoctorコマンドを実行しましょう。

$ flutter doctor

FlutterではSDKインストール後にこのdoctorコマンドを実行することで、Flutter実行のために不足している外部ツールやライブラリなどをエラーとして表示します。

以下はMac上で初めてdoctorコマンドを実行した際に出やすいエラーです。それぞれの対処方法を記述していきます。XCodeとAndroidStudioについてもインストールの有無がここで確認されます。

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, set ANDROID_SDK_ROOT to that location.
      You may also want to add it to your PATH environment variable.

このエラーはAndroidSDKをインストールしていないことが原因です。AndroidSDKがない状態でAndroidStudioを起動すると、「Missing SDK」という画面が表示されるのでそれに従ってSDKをインストールしましょう。

また、Android Build Toolsのバージョンが異なるというエラーが表示された場合には、AndroidStudioで[Preferences]メニューからAndroid Build Toolsのバージョンを最新にしましょう。

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    ✗ Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses

AndroidSDKを更新した後にこのエラーが表示されます。ライセンス確認が必要となるようですので、指定されたコマンドflutter doctor --android-licensesを実行しましょう。

複数回Accept?を確認されるので[y]を入力していきます。

[!] Xcode - develop for iOS and macOS (Xcode 11.2)
    ✗ CocoaPods installed but not working.
        You appear to have CocoaPods installed but it is not working.
        This can happen if the version of Ruby that CocoaPods was installed with is different from the one being used to invoke it.
        This can usually be fixed by re-installing CocoaPods. For more info, see https://github.com/flutter/flutter/issues/14293.
      To re-install CocoaPods, run:
        sudo gem install cocoapods

このエラーはCocoaPodsが存在しない場合に表示されます。表示された通りのコマンド sudo gem install cocoapods を実行しましょう。

[!] Android Studio (version 4.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    ✗ Unable to determine bundled Java version.

このエラーはAndroidStudioにFlutterプラグインがインストールされていない場合に表示されます。AndroidStudioで[Preferences]-[Plugins]にてFlutterDartのプラグインをインストールしましょう。

(2021/01/07 以降)AndroidStudio4.1では上記プラグインのチェックは通らなくなるようですので無視しても問題ありません。(詳細はこちら

再度doctorコマンドを実行し、以下のようにチェックマークが表示されれば完了です。

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Mac OS X 10.15.7 19H2 darwin-x64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.2)
[✓] VS Code (version 1.52.1)

さらに、VSCodeでもFlutter関連のExtentionsをインストールしましょう。以下の3つをおすすめします。

dart-code.dart-code
dart-code.flutter
nash.awesome-flutter-snippets

最初のプロジェクト

FlutterのGetStartedではflutterコマンドでのプロジェクト作成を説明していますが、ここではすべてVSCode上で実行していきます。

まず、[⌘]+[Shift]+[P]キーでコマンドパレットを開き、[Flutter: New Application Project]を起動します。プロジェクトを作成する場所を選択し、続けてプロジェクト名を入力します。今回はmtestというプロジェクト名にしました。これだけでFlutterプロジェクトが作成され、VSCodeの新しいウィンドウが開かれます。libフォルダ内のmain.dartがこれから編集するファイルですので、開きましょう。

VSCode左側メニューからデバッグボタンを選択し、[Run and Debug]から[Start iOS Simulator]を実行しましょう。XCodeで用意されているiOSシミュレータが起動し、ここで編集しているプロジェクトがiOSアプリとして実行されます(初回はビルドに非常に時間がかかるので待ちましょう)。

用意されているサンプルプロジェクトは、右下の[+]ボタンを押すと中央の数字が増えるようになっています。デバッガとして動作するため、ブレイクポイントの設置もできますし、ホットリロードも可能です。

iOSシミュレータが起動しない場合、[Start iOS Simulator]を実行した時点でMacDockにSimulatorメニューが表示されています。こちらを右クリックし、[Device]-[iOS 13.2]-[iPhone 11]のようにクリックするとシミュレータが起動します。iOSバージョンや端末種はお好みで。

さっそくソースコードを編集してみましょう。

ホットリロード

まずはかんたんにテキストを編集しましょう。

アプリ中央に表示されているテキストを「右下のボタンをクリック」と書き換えて保存します。書き換え箇所は lib/main.dart の101行目です。

書き換えたらすぐにアプリ内のテキストが更新されるところが確認できたでしょうか。

以上でFlutterによるアプリ開発の導入が完了となります。

引き続き、ウィジェットの設定やおすすめのディレクトリ構造、Firebaseとの連携などを記事にしていきたいと思います。

「手段が変わったとしてもゲーム開発に関わりたい」 コンテンツデザイン部 部長 大金翔吾インタビュー

0

「いいモノをつくるためにできることは全部やろう!」をミッションとするコンテンツデザイン部(以下、CD部)は、良質なゲームを受託開発という形で世に送り出しています。受託開発のメリットやチーム運営について大金さんに聞きました。コロナ対策のためにリモートワークが増えている今だからこその「コミュニケーション」についてもお話します。(2021年1月 取材)

大金 翔吾(おおがね しょうご)
2018年 アピリッツ入社
趣味はゲームと車と旅行です。
水樹奈々のライブに参加するのが生きがいで
いつかツアー全通を達成することが目標です。

今も昔も一番やりたいことは「ゲーム開発

ーー 大金さんがCD部の部長になるまでのお話を聞かせてください

2018年5月にアピリッツが株式会社風姿華傳のゲーム事業を譲受したタイミングで自分もアピリッツに参加しました。風姿華傳に入った当初はブラウザゲームのエンジニアで、アピリッツ入社時にはアプリのゲーム開発もおこなっていました。

その後、あるゲーム案件でクライアントエンジニアを担当しました。このときクラス設計もやることになったんです。

ーー クラス設計をおこなうのは初めてだったのでしょうか?

知識は持っていましたが、仕事として本格的にクラス設計をしたのは初です。正直「どうやってやるんだ!?」と探り探り手を動かしてました。でも自分が作ったクラス設計をもとにプログラムすると「ああ、この設計はダメだったんだな」「こう修正しよう」って勘所がわかってくる。いい経験でした。エンジニアとしての引き出しが増えたと思います。

その後、プロジェクトの都合で開発の現場から離れました。離れたあとは3Dグラフィックのプログラミングに挑戦したくてUnreal Engineを勉強したり……。でも「会社に来てまで勉強するのってなんなんだよ?」と思っていました。参考書なんてすぐ終わっちゃいますし、本当は開発の現場でガリガリとコードを書きたい。この時期はフラストレーションが溜まっていました。荒れてたなと思います。

ーー “荒れた大金さん”って、まったく想像がつかないのですが、荒れるとどうなるのですか?

もちろん会社のメンバーに八つ当たりとかはしませんけど、身の振り方を考えました。あと、ためしに「朝7時に出社して17時に退社する」とかやってみたり。これは意味がなかったですね(笑)何時に帰宅しようが結局ゲームしてましたから。

腐ってばかりもいられないので、自分を見つめ直しました。自分にとってエンジニアリングってなんなんだろうか、って。そこで、エンジニアリングは自分にとって「ゲーム開発の手段」であって、ツールのひとつだと気づいたんです。

今も昔も僕が一番やりたいことは「ゲーム開発」です。ツールが変わったとしても自分はゲーム開発に関わりたい。つまり、エンジニアリングにこだわる必要はないな、と。

同時に「もしエンジニアとして3Dグラフィックに関われないのなら、偉くなろう」と考えました。ドライな判断かもしれませんが、自分にとっては大切な目標です。

ーー 目標がはっきりわかっていると前に進みやすいですよね

「なんのためにこれやってるんだ?」と迷ったときに「これをやりきれば、こういう成果や報酬がある」と明晰にわかっていると進みやすいです。

ーー そこからマネージャーの道に進んだのですね

はい。演義シリーズのマネージャーに立候補して、運営業務の引き継ぎ、移管環境の構築、お客さまとのやりとりを担当しました。

ーー 社内のメンバーや社外のお客さまとのやりとりが一気に増えるわけですよね。コミュニケーションはもともと得意でしたか?

いえ、昔をふりかえると人見知りなほうだったと思います。でも、会話しないと仕事が進まないわけですから、環境に合わせて変わるしかない。だから最初はめちゃしんどかったですよ!

ーー めちゃしんどいけど、目的があるから……

そうです、乗り越えた先で手に入る成果がわかってるから、できる。そうしていくうちに前向きになりました。あと、同じことをずっと続けるのがつらいんだなってこともわかりました。自分は、ハードルが上がるとパフォーマンスが上がるタイプだと知りました。

組織の成長にも貢献できたと感じてほしい

ーー 大金さんはCD部でどのようにマネージメントをおこなっていますか?

今までの部長陣が敷いてくれた道があったので、自走できる優秀なメンバーがもともと揃っています。それぞれのメンバーを信頼して「頑張れるところを頑張れよ」と任せています。

そして最後の砦として自分がいるイメージです。危なそうになったら軌道修正をします。

「ここどうなってるの?」とマメに確認するようにしています。自分がわからなくて不安なところをつぶしていくと、安心してメンバーに仕事を任せられる。

ーー メンバーのキャリアをマネージメントする場合はいかがでしょう?

自分で目的を定義してもらい、どう進むかをイメージしてもらいます。マイルストーンも自分で考えてもらって、そこからは本人のスキルや適性を周りがどう引っ張り上げるか?を考えます。

仕事を任せるときも、キャリアの話をするときも「これをあなたに任せるのは、あなたができると思っているからだ」と伝えることを心がけています。そして「完遂したら、あなた自身とプロジェクトにどんなインパクトがあるか」も必ず伝えます。自分の成長だけじゃなく組織の成長にも貢献できたと感じるのって、うれしいものですから。

ーー 採用面接ではどんなところを注視しますか?

スキルや実績にくわえて「この人との会話は盛り上がっているかな?」は気にします。コミュニケーションあってこそのゲーム開発なので。雑談からうまれる画期的なゲームの機能や遊びってありますし、問題解決にもつながります。

受託開発で得たノウハウを社内に還元する

ーー CD部は基本方針に「コミュニケーションは業務の一部。ためらわずに積極的に」と明記しています。具体的にどんなコミュニケーションをとっていますか?

受託開発のメリットは他社の開発スタイルを間近で学べることです。ノウハウを社内に還元しています。AG部の吉田さん主催のエンジニア文化共有会や、CD部のプランナー会で共有しています。とくにプランナー会は僕が「やれ」と枠を作ったわけじゃなく、僕や和田翔平(CD部のGM)が「やったほうがいいんじゃない?」と促したら自発的にみんなが企画して、どんどん発展していったのでうれしかったです。

ーー 大金さん自身のコミュニケーションはどんなスタイルでしょう?

自分の中に「パブリックな自分」を作っています。まず、全体への指示は、あいまいさを残さず理路整然と伝えます。そして、プロジェクト単位のやりとりやコミュニケーションの枠が小さくなるに従って、自分の個性を出していくんです。そこで「楽しげだな、この人と仕事すると楽しいな」と思ってもらいたい。

最近とくに心がけているのは「いいね!」ってポジティブな言葉を伝えることです。部内にはいろんな性格の持ち主がいますが、ほめられてうれしくない人はいないはずです。

ーー みなさんうれしそうな顔をされてますか?

いや(笑) そんな大反響はないですけど、時々はにかんでいる人をみると「よし!」と思いますね。

大反響はないけれど「褒め」は続行します

リモートワークで得た教訓

ーー コロナ禍で「出社して働く」前提が崩れました。アピリッツも2021年1月の緊急事態宣言にあわせて出社率を大幅に下げています。リモートワークの課題は何でしょうか?

まず、対面で伝わっていたことをいかにしてリモートで共有するか、です。2020年4月の緊急事態宣言のタイミングで得た教訓です。

たとえば、運営しているタイトルで不具合が出たとき、最初に異変に気づいた人がチャットで発言しても緊急度が周囲に伝わらないことがありました。今は、発信と対応のフローを整備して、メンバーで守るように徹底しています。

あとは朝会は絶対に必要です。ほんの数分でも、メンバーの表情や顔色を知ることは仕事のパフォーマンスや本人のケアにつながります。

今も残る課題は「ちょっといいですか?」と気軽にすぐ相談できる環境をつくることですね。3分話せば解決できそうなことを、いかにオンラインで解決するか。

ーー 年始に緊急事態宣言がそろそろ出るかも……というタイミングに、大金さんは部内に向けて「続報を待て」とすぐ発信していました

そこはパブリックな自分として発信しました。最初の緊急事態宣言が発令されたあとアピリッツは全社でリモートワークを実施しました。そして、緊急事態宣言が解除されてからは出社比率を上げていました。健康上の理由や家庭の事情については継続して個別に対応していますが、部内で「ずっとリモートワークしたい」という声ももちろん上がりました。

彼らの気持ちもわかります。ですから、全体に対して「なぜ出社が必要なのか」について対話を重ねました。コミュニケーション不全で失敗したことや、仕事のクオリティを高めるときに対面が必要な場面もあるよ、と。少しずつ理解を得ていきました。

方針や目的を理路整然と繰り返し伝え、理解を得ることもコミュニケーションなんですよね。

僕個人としては、正直「かっこつけたい」みたいなところはあるんですよ。「リモートでもパフォーマンスを一切おとさず、しっかりやる」って。とはいいつつ、泥臭く対話を重ねることの大切さも痛感しているので、うまく折り合いをつけていきたいです。

ーー 2021年、どんなことを挑戦していきたいですか?

個人的には、ビジネス拡大に全力をかたむける一年にします。目標はDB部の長谷さんですね。

そして、部としては、CONNECTさんと開発した「ひよこ社長のまちづくり」に続くようなゲーミフィケーションの領域に挑戦していきます。新しいプロダクトを出したいです。

関連記事:アピリッツのその他の役員インタビュー

リモートワークがつらい… 身の回りですぐできる具体策【7選】

0

はじめに最初はリモートワークがつらかった

コロナ禍によって出勤勤務から在宅勤務(リモートワーク)を始めた人が増えているかと思います。
働く場所が変わったことで大なり小なり働き方に影響が出てきますよね。メリット・デメリット両方ありますが、環境の変化に適用できずにつらい思いをしている人もいらっしゃるのではないでしょうか。かく言う私もリモートワークを去年(2020年)の4月から始めて、ちょっと慣れてきた5日目くらいが一番つらかったです。今まで上手くできたことができなくなり、周りに誰もいないのでそれに気づいてくれる人もいませんでした。

工夫することでつらさを軽減

幸いにも私の場合は少しの工夫することで、つらかった気持ちがすぐに普段通りくらいになりました。今回は、どのような工夫をしたら浮上できたか、実体験を元に具体策を挙げていこうと思います。働き方は人それぞれですので、働く人の全員にこの記事が当てはまることはありませんが、参考程度に使えそうなものだけピックアップしていただくといいかと思います。

7つの具体策

  1. いま考えていることをメモや分報にそのまま書く
  2. 終わったタスクは目立つように赤丸⭕️をつける
  3. 照明の明るさを変える
  4. リマインダーでタスクを忘れる
  5. タイマーをかける
  6. 立って作業をしてみる
  7. ラジオ体操をする

ツールを活用する方法

いま考えていることをメモや分報にそのまま書く(おすすめ度:★★★☆☆)

私の場合、仕事をしていると考えることが多く、頭の中で交通渋滞を起こしがちです。作業がうまく進められないことの悩みだったり、急に思い出したタスクだったり、外で雨が降っているかどうか気になったり。そんなときに私がおすすめするのは、そういう日常の思考を断片的な言葉にして書き出すことです。同時に色んなことが気になってどれにも集中できないときに、書き出した内容を眺めて自分の思考を交通整理できます。
少し話が変わりますが、弊社では主なコミュニケーションツールとしてslackを使っており、個人の分報チャンネルを作って発信するのが流行っています(ざっと調べてみると100人分くらいチャンネルがありました)。分報とは今やっている作業や困っていることをひとりごとのようにつぶやいていくことです。自分の分報チャンネルに他の人も入ってもらうことで、Twitterのようにリアルタイムに自分の状態を共有できます。(参考: http://c16e.com/1511101558/

私の分報チャンネル。「(勤怠の)打刻してなかった…!」という嘆きに、チャンネルに参加している人から絵文字でリアクションが来ています。

分報が合う・合わない人はいると思うので、手元のメモアプリなど他の人から見えない方法でもいいかと思いますが、自分が思ったことを率直に書ける場所をもっておくことは精神衛生にも良さそうです。

終わったタスクは目立つように赤丸⭕️をつける(おすすめ度:★★★★☆)

1日の初めにその日のやることリストを書き出す人は多いかもしれません。ひとつ作業を終わらせるたびにリストを取り消し線で消したり、チェックボックスに印をつけたりすることで「この作業は終わった」ということがひと目見てわかるようになります。私の場合は、slackの分報に「済スタンプ」と一緒に投稿しています。スタンプでも赤丸でも何でも良いのですが、ここでのポイントは目立たせることです。

タスクが終わったことが目立つように赤丸の「済」スタンプを多用しています。

一人でずっと作業をしていると終わりがないような気持ちでしんどくなってきてしまいますが、ひとつやり遂げたことを自分自身にアピールすることで達成感を持つことができます。なかなか作業が終わらない時は今の作業をもっと細かく分割して書き出して、小さなゴールをたくさん用意します。細かいことでもひとつ終われば自分を褒めてあげるつもりで赤丸をつけてあげることで「よくやった。終わらない仕事はない」という気持ちになります。

照明の明るさを変える(おすすめ度:★★★☆☆)

画像:Unsplush

会社の照明は作業をするのに一番良い明るさに設定されていますが、リモートワークの作業場となる部屋の照明はそうじゃないこともあるかと思います。自室の照明はリモコンで明るさを変えられるタイプで、業務時間中は一番明るい全灯にして休憩時間や業務後は一番暗い設定にしています。目に入る光の量を変えることで、仕事中の集中モードと休憩中のリラックスモードを自然と切り替えることができます。
ご自宅の照明環境は人それぞれかと思いますので明るさを変えられない場合もあると思います。が、明暗を調整できれば良さそうなので、卓上ライトのオン/オフを切り替えたり、カーテンの開け閉めをしたりすることで調整することもできそうです。
特に休憩中に暗くすることが大切だと感じています。一日中明るいと心が休まらず頭がずっと活動状態になってしまい、ついつい仕事の残りのタスクのことを考えてしまいます。休む時は仕事のことをいったん置いておくことで、気持ちをクールダウンすることができます。

リマインダーでタスクを忘れる(おすすめ度:★★★★☆)

リモートワーク中、他の人からのメッセージや顧客からのメールなどで新たなタスクが増えることもあるかと思います。新しいタスクの優先度によって今やっている作業を続行するか新しいタスクに取り掛かるか変わってきますが、どちらにしろ「今はやらないタスクを覚えておく」という状態が発生します。ただでさえ作業を進めるだけでも精一杯なので、すぐにそのタスクのことは忘れて作業に戻りましょう。とはいえずっと忘れっぱなしは困るので、いつ思い出すことにするかだけ決めてリマインダーを設定することで心置きなく忘れることができます。
リマインダー機能のあるツールはいくつかあると思いますが、私はここでもslackを活用しています。タスクの内容を分報に書き出して、リマインドするタイミングを「20分後・1時間後・3時間後・明日の朝9時」から手軽に選ぶことができます。カスタマイズから指定の日時も選べます。通知が来た後のスヌーズも、いつ再通知するか選ぶことができます。

「後でリマインドする」のメニューからいつ再通知するか選ぶことができます。
時間が経つとこんな風にメッセージが来ます。

「今は目の前のタスクに集中したいから3時間後に考えよう」とか「今日やろうと思っていたけど、今やっているタスクが思ったより重かったから明日に回そう」とか、適切なタイミングで思い出すことができるので安心して忘れることができます。頭の作業領域を「これやらなきゃ」「あれやらなきゃ」で埋めてしまわないことが狙いです。

タイマーをかける(おすすめ度:★★★★★)

スマホのタイマー機能やキッチンタイマーなどを使って15分ごとにアラームを鳴らします。効果は「我に帰る時間を強制的に作れる」です。(15分は目安なのでお好みで!)ひとりで黙々と作業していると「自分」と「今やっている作業」がすべてになってしまい、仕事の全体像が見えなくなりがちです。定期的に自分の現在地を確認することで、次にやることへの見通しを立てたり、なかなか進まないタスクを一旦切り上げたりすることができます。私の場合は、このタイミングで一息ついて水を一口飲んでいます。さらに時間の区切り(始業・昼休憩・終業)でもアラームをつけることで、オンとオフの切り替えの手助けになります。タイマーさえあればすぐに始められるところもおすすめポイントです。

iPhoneのアラーム機能を活用して、学校のチャイムのように定期的に音を鳴らします。自宅なので周囲の目を気にする必要なし!

体を動かす方法

立って作業をしてみる(おすすめ度:★★★☆☆)

画像:Unsplush

立って働いているオフィスワーカーの人がいると聞いて実際にやってみました。昇降式の机があるとPCも一緒にあげることができていいのですが、そんなものは無いので机の上に台や椅子を置いて高い位置にPCを配置しました。気分をガラッと変えたいと思った時に突発的にやると良かったです。物理的に視線が変わることで強制的に気分が変わります。
私の場合はプラスアルファとして、好きなBGMを鳴らしながら踊りながら仕事をしています。テンションが上がるので単純作業などに向いています。ずっと動いているのも疲れるので30分程度が限界です。

ラジオ体操をする(おすすめ度:★★★★☆)

ラジオ体操は3分程度で終わるので、ちょっと体を動かしたいときに最適です。業務開始前に体を動かしておくと、頭もだんだん働き始めるような気がしています。
iPhoneをお持ちの方でさらにおすすめなのが「オートメーション」という機能で毎朝決まった時間に自動でラジオ体操を流れるようにすることです。時間になったら通知が届き、ワンタップだけでラジオ体操の曲が流れ始めるので「しょうがないやるか〜」と自然に動き始めることができます。

毎朝9時に一連の処理をするようにオートメーションを設定しています。ヘルスケアサンプルのアプリケーションで体温を記録させてから、ラジオ体操が流れるURLが開きます。

おわりに:大切な具体策をもうひとつ

いかがでしたでしょうか。長々と書いてまいりましたが、ここまで読んでいただきありがとうございます。今回取り上げたリモートワーク以外でも、仕事上のモヤモヤは色んな工夫で乗り切れると嬉しいですね。
ただ、正直リモートワークがつらい要因は個人の工夫だけでは解決できないことも多いので厄介です。コミュニケーションがうまくいかないことのモヤモヤや自宅の環境が仕事場として整っていないこと、などなど。工夫しても上手くいかなければ「他の人に相談することが仕事だ」と視点を切り替えてみてもいいかもしれません。自分だけでなんとかしようとせずチームで乗り切ることも「仕事を遂行する」という目標において大切になってきます。また、仕事の進捗に関係なくても、つらい気持ちを誰かに打ち明けると何か道が開けるかもしれません。誰かに相談することも具体策のひとつです。
コロナ禍での2回目の緊急事態宣言で、一度は減ったリモートワークが復活して憂鬱な方もいらっしゃるかもしれません。休むときはしっかり休んでご自愛してくださいね。お互い支え合って工夫で生き抜いていきましょう!

Webデザイナー1年生におすすめするデザインの練習方法

0

こんにちは。デジタルビジネス部のWebデザイナーAです。

今回は私がWebデザイナー1年生の頃にやっていたデザインの練習方法について紹介します。
皆さんがバナーやサイトのメインビジュアル、Webサイトのデザインを制作するときに少しでも役に立てれば幸いです。

私が実践していたのは以下の4つです。

  1. デザインを見て学ぶ
  2. Webサイト以外のデザインから学ぶ
  3. デザインを真似して学ぶ
  4. 学んだことを応用してオリジナルのバナーやサイトのデザインを作ってみる

1. デザインを見て学ぶ

最初はとにかくいろんなサイトを見ることを意識してやっていました。
あとはグロナビやボタン、アイコンなどのパーツ単位で気になったデザインをエクセルにまとめて、デザイン制作で悩んだときに見直せるような資料も作っていました。

流行りや最近のデザインの傾向を知ることにも役に立ちますし、何より制作意欲への刺激になります。
例として私が普段見ている主なサイトも掲載しておきます。

Webデザインのまとめサイトの例

WebDesign
国内サイトだけでなく海外サイトまで幅広く網羅。
デザインの参考になるクオリティーの高いサイトが約2800件掲載され、カテゴリー検索だけでなく、タグ検索、レイアウトタイプやメインカラーでの検索も可能。

SANKOU!
国内サイトのみをピックアップ。
カテゴリ検索の内容が具体的。(例:シズル感・訴求力がある写真・動画・映像)
フィルター検索で細かい絞り込みも可能。

81-web.com
国内サイトのみをピックアップ。
サムネイルにhoverするとサイトに該当するカテゴリ・カラー・タグを見ることができる。
サイトのお気に入り登録機能が便利。(Webサイトのボックス右下にある+ボタンで登録して、メニューのFavoriteから登録したサイトを閲覧できる)

MUUUUU.ORG
クオリティが高く縦に長いサイトがピックアップされているので、TOPに情報や写真を多く掲載するサイト制作時に参考になる。

bookma!
サムネイルにPCとスマホの表示画面が一緒に掲載されているため、レスポンシブデザインをする時の画面の見え方のイメージを膨らませやすい。
1サイト1カラム構成になっているので、色んなサイトのファーストビューをじっくりみたい人におすすめ。

1GUU
国問わずとにかく色んなサイトをみたい人向け。
国内と海外サイトが掲載。アニメーションのあるサイトはサムネイルの時点で動きの確認ができる。海外サイトの国別または7大州ごとに絞り込み検索が可能。

Pinterest
Webサイトに限らず色んなデザインを集めたい人向け。
ユーザー登録(無料)の必要あり。
該当する画像をボード(ブックマークフォルダ)にピン留め(ブックマーク)するサイト。
ボードには任意の名前をつけられ、他のユーザーのボードもフォローして閲覧することができる。

2. Webサイト以外のデザインから学ぶ

雑誌や広告のレイアウトもWebサイトのメインビジュアルやコンテンツのタイトルデザインを作る上で役に立ちました。

雑誌や広告はWebと同じく限られた空間に情報をわかりやすく見せ、かつ掲載されている内容にあったデザインがされているので、普段からジャンル問わずチラ見しておくと何かの役に立つ時が来ます。
実際、私もファッション紙やデザイン情報誌などから発想を得た経験があります。

見ておくと良いポイントとしては、文字間や文字の配置とデザイン、使われている色、イラストやデザインの配置、ロゴの配置などです。
あとは細かい装飾の部分で、アクセントになっている遊びの部分なども意識して見ていました。
(手書きのイラストや文字、筆記体の文字、アナログ素材(紙など)で柔らかさを出している背景、背景色から少しずらして配置されている写真など)

3. デザインを真似して学ぶ

気になったサイトやレイアウトがまとまって見やすいバナーなどをスクリーンショットして、Photoshopで上からデザインをなぞっていました。

実際に自分で真似して作ることで、文字の間隔やサイズ、フォントの種類はどんな系統のものが使われているのか、どんな加工や配色になっているか、写真やイラストなどの配置がどんな風に作られているのかがわかります。

実際に手を動かすことで、見るだけでは得られない数値単位での情報やデザインの技術が自分の中に自分の中にストックされていきます。

4. 学んだことを応用してオリジナルのバナーやサイトのデザインを作ってみる

今までの3つを踏まえた上で、架空のクライアントを立ててオリジナルのデザインを作ると、さらに自分の力になります。

架空のクライアントが思いつかない場合は、自分の趣味や好きなものを題材にしてみるのも良いです。
Webサイトのデザインを作った場合は、コーディングまでやってみるとさらに力が尽きます!

最後に

以上、4点を業務の隙間時間に少しずつ積み重ねてやっていくと、実際の業務で役に立つことがあるでしょう。

是非、実践してみてください。

「育児も手続きも段取りが大事!」男性の育児休業について

0

政治家が男性育児休業を取得したことが話題になるなど男性育休に対する社会の関心は高まりつつあり、取得率も上昇しています。でもまだまだ少ないです。先日アピリッツの男性社員が育児休業を取得しました。アピスピにも何度か登場してくれている3DCGデザイナーの立原さんです。手続きや育休中の様子、育休明けの仕事について教えてもらいました。(2020年 12月取材)

プロジェクトメンバーの後押しで育休取得

ーー 「育児休業を取ろう!」と決めたキッカケを教えてください

人事企画部の方との世間話で妻の妊娠を話したことが始まりです。「おめでとう! 育休取れるよ!」と言われて「いいんだ!?」と思いました。相談しようかなとは少し考えていたのですが、先に提案してもらえました。

家族も「あ、取れるの? よかった!」といった反応で、喜んでくれました。

ーー 育休取得の手続きや相談はスムーズに進みましたか?

はい。手続き面は人事企画部の川口さんと大越さんが「育児休業給付金」や「健康保険」を調べてくださり、フォーマットも作ってくださったので、すごく助かりました。自分でIT健保に相談して進めようと思っていたので……。

仕事面は、プロジェクトリーダーの和田さんやメンバーが「ぜひ取って!」と快く応じてくれたのでありがたかったですね。ふだんから仕事を1人で完結させないでいろんな人に見てもらっていたので、安心して送り出してくれたのかな、とも思います。

日頃からのコミュニケーションの大切さをあらためて感じました。

また、あらかじめ後輩に仕事を共有して教えてきました。みんなが成長してくれたことも今回の育休取得の後押しになったと思います。

ーー 育休に入るまではどのような準備をしましたか?

まず、仕事の引き継ぎです。自分の作業を早めに片づけて準備しました。同時に妊娠中の妻のケアもあったので肉体的にも精神的にもエネルギーがいりました。

しかも出産予定日よりも早めに産まれたんです。手続きや引き継ぎを一ヶ月以上前から進めていたので間に合いましたが、ちょっと焦りました。ですから、これから育休を検討する方は早め早めの準備をおすすめします! 赤ちゃんには赤ちゃんのスケジュールがあるので、こちらの想定と全然ちがう進行だって十分ありえますから!

「大変なこともいっぱいあるけれど、愛しさがまさりますね」と立原さん

ーー 育児休業は何日取得しましたか?

21日間です。和田さんからは「一ヶ月でも二ヶ月でもいいよ!」と言っていただけたのですが、ちょうどプロジェクトのリリースが近づいていたので、もろもろ考慮して今回の育休は21日間に決めました。

ーー 育休中はどんなことをしましたか?

料理・掃除・夜中の育児は自分担当としました。夜中は妻に寝てもらいたかったので。洗濯は妻にお願いしました。その他の家事は「できる人がやる」と臨機応変に分担しました。妻の母親と同居しているので、たびたび手助けしてもらえています。

タイムテーブルは次のような感じです。

時間やること
0時ミルク
趣味の時間
睡眠
4時ミルク
睡眠
7時ミルク
朝食
10時ミルク
昼食の支度
昼食
13時ミルク
グラフィックの勉強
16時沐浴
ミルク
グラフィックの勉強
夕飯の支度
19時ミルク
夕飯
風呂
21時ミルク
寝る準備
寝室でのミルクや空調・加湿器の準備
24時ミルク
新生児のお世話の一部

ーー ミルク、3時間おきなんですね。赤ちゃんって一日八食……?

はい! 産まれてすぐのころは赤ちゃんの体もお腹も小さいので、少し飲むだけですぐお腹いっぱいになるんです。育休に入る前は「空き時間にCGの勉強をするぞ」と思っていたのですが、フタを開けてみたらそんな時間は全然なかったです(笑)息子はあまり寝ないで起きていることが多い子なので、随時おむつを交換したり、あやしたり……。できるだけ妻とも会話をたくさんするようにしました。

復帰後の生活リズムを予行演習

ーー 復帰に向けてどんなことを意識しましたか?

まずは家庭内の体制づくりです。私が復帰したあとの育児の分担をどうするか話し合って、その生活リズムをあらかじめ作っておきました。家族みんなが健康でいてほしいので、いきなり日常が変わって体調が崩れないように気をつけました。

ーー 生活リズムって大事ですよね。育休中、仕事は気になりましたか?

仕事、恋しかったですよ! アピリッツでのお仕事はどれも好きですし、私が育休中に作業を負担してくれたプロジェクトメンバーへの感謝と申し訳なさがあったので。それに、私自身、周囲から取り残されていく焦りもありました。プロジェクトの進行状況もとても気になりましたし。

なので、一年以上育休を取る方々の大変さや焦りに少し共感できるようになったと思います。

ーー 復帰後、仕事のすすめ方は変わりましたか?

なるべく時間内に仕事を終わらせて帰るようにしています。育休に入る前は引き継ぎ作業などで残業しがちでしたが。育休があけたあとも夜中の育児は自分が続けています。

ーー え! 眠れていますか?

まとまった睡眠はとれないので、眠いです! でも、ちょっとずつ泣く回数やミルクの回数も減ってきて、子どもの成長を毎日感じています。毎日うれしさがあります。2020年のクリスマスは、初めて家族と子どもと過ごしました。息子はまだわからないはずですが、大きくなったら「最初のクリスマスはこんなだったんだよ」って見てもらいたくて、記念にムービーや写真を撮りました。

ーー あらためて育休を取得していかがでしたか?

取得して本当によかったと思います。出産って本当に大変なことでした。お母さんは身も心もボロボロになります。パートナーが一番つらくて大変なときに側にいることができてよかったです。あと、段取りの大切さを痛感しています。育休の準備も、夜中のミルク作りの準備も、どちらも段取りが肝心ですよ!

ーー ありがとうございました!

関連記事:立原さんのお仕事に関する記事はこちらです『次元が一つ増えることで表現は倍増する」今需要が高い3Dデザイナーと、3DCGの制作工程を紹介!

売れるゲームとは?面白いゲームとは?企画の育成プロセスをまとめてみた

0
ゲームアイディア
売れるゲームとは?面白いゲームとは?

コンテンツデザイン部 A(仮)です。

アナタの考える売れるゲーム・面白いゲームはなんでしょうか?

本記事はその『アイディア』を育成させるプロセスをまとめます。

※個人の記事執筆であり、会社としての見解ではございません。


0.その前に…なぜそのゲームか?

売れるゲームとは?

遊んだら「面白い」ゲームは売れない

2020年現在、ゲーム市場は数多くのゲームであふれ、且つ多くが基本無料(Free-to-play)のゲームです。

アナタは今年、いくつのゲームを知り、いくつのゲームを触り、そしていくつのゲームを遊んだでしょうか?

それから言えることは「パッと見よくわからない(興味をそそられない)から無料であってもやらない」「少しだけ触って辞めた」が大半ではないでしょうか?

1時間プレイして面白さがわかるゲームを売ることはとても大変です。それはCAC・CPI(顧客獲得単価)にも直結します。

パッと見で面白さへの体験イメージがつくクリエイティブ(タッチポイント)は最低条件であり、さらにモバイル環境のユーザーだと仮定すると数分で「面白い」を味合わせることができることも必要です。

面白いゲームとは?

ゲーム業界内ではよく言われることではありますが、

第一欲求を動かされ、それを満たせるかどうか。

カタルシスがあるかどうか。

https://www.famitsu.com/serial/chasergame/202003/09194054.html
https://gamebiz.jp/?p=142333

しかし、そもそも「面白い」とは不確実な価値でありKPIの視点では推計が行いづらいです。

ですが、売れた面白かったゲームは数字で説明が必ずつくと思っています。(実際に数値化しているかどうかは別です)

よって売れる面白いゲームへの予測精度は高められると考えており、本記事ではアナタの新しいアイディアに対してただ「それ面白いの?」ではなく、フレームワーク的に数値化&検証精度をあげていきます。


1.アイディア育成のプロセス

1.1ロードマップを大枠で書く

・顧客の欲求のステージと価値のレベルはリンクしていますか?

ロードマップ

全体構造をまとめましょう。そのアイディアがもたらす、欲求の最終ステージから逆算して考えていきましょう。価値は数字などは使わず大枠イメージでこの段階では問題ありません。

1.2KPIツリーを作成する

浮かんでいるシステムイメージやジャンルを元に当該システムを採用している類似競合から各KPIを調査します。

類似競合のインストール数・ARPDAU(日別平均ユーザー数)・RR(継続率)・PUR(課金率)などから、推計しましょう。(マーケディングツールを用いると効率的です)

また後記の1.3,1.4を行っている段階で、獲得コストや開発コスト等のコスト面も逆算して追加推計していきます。

1.3市場規模を調べよう

TAM,SAM,SOMのを複数の角度で推定できますか?

・SOMとファイナンシャルズ(KPI)の規模感はあっていますか?

市場規模

初めにトップダウン分析を行います。次に1.2のKPIを含めボトムアップでも分析を行います。両方の視点から行うことにより、“ズレ”がないか”偏り”がないかを見直すことができます。

トップダウン例:[TAM]2019年世界モバイルゲーム市場は7兆1840億円 [SAM]××アクションカテゴリだと○兆○○○億円 [SOM]そのうち□□%シェア獲得で○○○億円

ボトムアップ例:1.2のKPIから、顧客数×顧客平均単価でSAMへの推定。その顧客のサービスに対するニーズをどのようにして市場を作り出し売っていくか、顧客のニーズを定量調査しまとめます。IPが決まっている場合は、ファンの想定母集団と想定購買力からも推計することができます。

1.4 UIフロー + モチベーション + ロイヤリティ

1.1~1.3までを深掘りしていく

UIフロー + モチベーション + ロイヤリティループ
※本画像は簡易的な製作イメージです

画面遷移項目(≒UIフロー)に、『モチベーション(気持ち)』+『ロイヤリティ(お金)』を入れ込みましょう。

本図を作る際、すべてを初めから作ろうとせず徐々にブラッシュアップましょう。また1.2&1.3より、各画面遷移別で『モチベーション(気持ち)』『ロイヤリティ(お金)』の”予測数字”をできるだけ細かく記載できるようにしましょう。ユーザーの成熟度に応じて記載するとより精度が上がります。

モチベーションやロイヤリティがループしているかを必ず見直しましょう。

※売り切りモデルは『ロイヤリティ』を省きます。


2.まとめ

本記事は読むだけではなく、実際に書き落としこむことが大切です。

1.1~1.4までを繰り返し書き終えているころには、アナタの考える売れる・面白いゲームは、価値の数値化や仮説検証までができているでしょう

今回の記事執筆の背景として、現状改めて可視化・蓄積していくことがこれからのゲームクリエイターはより一層必要なことなのではないかと感じているからです。

参考文献:ダイアモンド社『世界標準の経営理論』,㈱グロースハックスタジオ『THRUSTER』,㈱アンド『ビジネスフレーム図鑑』

▼「具体例や実際の値はないのか。なんだ。」と思った方以下よりお問い合わせください。また異業種であってもゲーム要素(ゲーミフィケーション)でのソリューション提供を弊社では行っております。

▼またここまで読んでいただいた、売れるゲーム・面白いゲームを創りたいと真剣に考える方、そういった組織・環境に興味がある方、ぜひ私と一緒にお仕事をしませんか?

DAU30万を想定したソーシャルゲームの負荷試験の為の事前準備

0

 こんにちは。CD部の金井と申します。今回は大規模な負荷試験の準備に関する事を書いていこうと思います。

そもそも負荷試験って何の為にやるの?

 リリース当初のゲームに良くありがちな事ですが。
 ユーザーアクセスの集中によってサーバーが落ちてしまい、そのまま長期メンテナンスに入った、と言うような事柄は目にした事があると思います。
 他にも新イベントが実装された時や期間限定のガチャが開催された時にユーザーが数多に戻ってきて、レスポンスが重くなったり。
 端的に言うならば、負荷試験はそのようなサーバー不具合を防ぐ為に行うものです。
 もう少し具体的に書くならば、

 リリース前に行う負荷試験としては、

 ・初日に起こり得るであろうリセマラに対して
 ・実装したイベントに対して
 ・また全てのAPIに対して


  ・レスポンスは許容出来る時間内に返せるか?
  ・用意したAPIサーバー、データベースサーバー、キャッシュサーバー、リアルタイムサーバー等々は想定したユーザー数のプレイに耐え得るか?
  ・想定以上のユーザー数がプレイに興じた場合どのような影響が発生するか? サーバー自体は落ちずに、レスポンスが重くなる程度の影響に留められるか?
  ・万一どこかのサーバーが落ちた場合、障害によって如何なる影響が発生するか? ユーザー不利益は発生しないか? 自動復旧の仕組みは整っているか?


 という事を確認する必要があります。
 また、リリース後にも新機能の実装時などには負荷試験を行うべきですが、その時は新しく実装された、影響された範囲だけを追加で調査すれば基本的に大丈夫ですので、そこまで大変ではないです。

新機能のリリース1週間前に負荷試験にて巨大なボトルネックが発見されて、やり直しになったテストフェーズに泣くQAチーム

負荷試験の為に何を準備すれば良いの?

 端的には以下の3つです。

  1. どのような負荷試験を行うか、調査する事を明確に定めた負荷試験計画書
  2. 実際にサーバーに対して負荷を掛ける、リクエストを投げる為のシナリオプログラム
  3. そして、負荷試験の為の環境

 一つ一つ見てきましょう。

スケジュールが緊迫しているというのに、こんな時に限って会議の為の部屋が全て埋まっていてミーティングが出来ないエンジニア

1. 負荷試験計画書

 これが無いと負荷試験は始まりません。
 当たり前な事ですが、明確な目標やゴールが見えないままに負荷試験を行ったところで、大した成果物は発生しません。
 その為に、上記で書いたような事を明確な数値、試験内容として定める必要があります。
 例えば、

  • 想定DAU(Daily Active User……1日に遊ぶユーザー数)は30万人とする。
  • サーバーのCPU、メモリはユーザーが最もプレイする時間帯でもそれぞれX%, Y%までに留まるようにする。
  • 負荷試験中にユーザーデータを保存しているデータベースの1台を落とす。N分以内に自動復旧し、正常に遊べるようになる事を確認する。

 等々とても割愛していますが、様々な状況を想定して、それらに対する目標値を定めなければいけません。

 さて、ここでタイトルにもあるようにDAU30万を想定するならば、RPS(Request Per Second……秒間に飛んで来るリクエストの数)はどれ程を想定すれば良いのかを算出してみましょう。

 計算式は以下です。

 RPS = DAU × 最大でどれだけの割合の人数が同時に遊ぶか × リクエストは何秒に1回叩かれるか

 まずDAUは、上の人……要するに製作しているゲームのターゲット層、想定プレイ人数を定めているお偉い人から聞き出しましょう。ここでは表題の通り、30万とします。
 次に最大でどれだけの人数が同時に遊ぶかですが、これに関しては自分の経験にはなりますが、DAUの10%~30%で定めた事がありました。ここでは多めに30%としておきましょうか。
 そして最後のリクエストは何秒に1回叩かれるかに関しては、これは実際に遊んでみて確かめてみましょう。ここでは10秒に1回サーバーにリクエストが飛ぶ、と仮定しましょう。
 すると、上の式は以下となります。

 RPS = 300000 × 0.3 × 0.1
 RPS = 9000

 要するに、秒間に9000のリクエストが捌ければ良い訳ですね! 大変だぁ。

 また、負荷試験というのは最初からこんな9000RPSなどといったデカい値を数多のサーバーに対してぶん投げるのではなく、サーバー単体での性能から測っていくものですが、この単体の性能が貧弱だと想定人数を捌く為に必要なサーバー台数も必然的に爆上がりします。

 例:
 1サーバー辺りのスレッドが20あるとして、リクエストが平均200msecだった場合、そのサーバー1台が秒間で捌けるリクエスト数は 20 * 1000/200 = 100となる。
 9000RPS…秒間リクエスト9000を捌く為に必要なサーバーの台数は9000/100 = 90台。
 また、スレッド数20を実現出来るサーバーは、AWSだとオンデマンドで大体1時間に1\$の料金が発生するサーバーになる為、この性能をオートスケーリングとか何もなしでオンデマンドで常に立てておくと、一月辺りの料金は、

  • 1日に1台で掛かる料金が24\$
  • それが90台で30日の2700倍で64800\$

 日本円に換算して大体674万円!
 ひゃっほう!
 因みに言うとこれ、APIサーバーだけで掛かる金額なので、データベースサーバーとかキャッシュサーバーとか鑑みるともっと増えます。

 何が言いたいかと言うと、サーバーコストを削減する為にも綺麗で速いコードと言うのは常日頃から心がけておくべきですね。リファクタリングによって月100万単位でコストを削る事も可能になるかもしれませんよ。
 まあ、上記の例だとリファクタリングより、スポットインスタンスやらオートスケーリングやらを活用した方が安くなると思いますけど。

現状の性能から試算されたサーバーコストに泣くディレクター

2. シナリオプログラム

 準備が一番大変なのは、計画書よりも環境よりも、こいつです。
 結局、疑似的にクライアントを作るようなものですからね。
 基本、全てのAPIに対して投げられるようにシナリオプログラムは作ります。そして、データベースのインデックスが効いているか等を確かめる為にも、ある程度ランダム性も持たせなければいけません。
 場合によっては、暫く待たなければ結果が出来ない仕様のデータを早送りして即座に結果を受け取れるようにさせる、フレンドからの干渉によるデータを疑似的に作成する、等といった負荷試験専用のデバッグAPIなどをSV側に作ったりする必要も出てきます。
 これに関しては開発中からコツコツ作っておくのが吉だと思います。負荷試験をすると決めてから作るとした場合、余裕で二週間とかは掛かると思います。

 また、その負荷を掛ける為のツールは幾つかありますが、自分はJMeterLocustに関して使用経験があります。

 JMeterはシナリオに書き辛い部分があったり、実際に負荷試験本番で使う場合はCUIから結構複雑なコマンドを投げたりしなければいけませんが、出力結果を纏めたり比較したりするツールがGUIに内包されており、そこは便利です。

 Locustはシナリオは書き易く、実際に負荷試験本番で使う場合もGUIを使って簡単に操作出来ますが、結果はCSV等に出力出来るだけで、そのCSVからまた色々比較検討する際にはExcelなどを使わなければいけません。

 総合的に言えばLocustの方が良い印象です。
 負荷試験はプロジェクトで一回切りのものでもありませんし、手間を掛ける煩雑さに関しても

 負荷試験を実行する > 負荷試験の結果を纏める

 な事には間違いありませんから。

負荷試験に必要な100近いAPIのシナリオを書くのを1週間で命じられたエンジニア

3. 負荷試験の為の環境

 リリース後にも負荷試験を行う必要性が出てくるであろう事も考慮すると、リリース前の本番環境を負荷試験環境にしたりするのはあんまりお勧めしません。
 ただ、基本的に使う必要の無い負荷試験環境を立てっぱなしにしていては、勿論無駄なお金が掛かります。
 また負荷試験の実行フェーズでも、本番環境と同等の環境にしていた場合、負荷試験をしていない時間には出来るだけサーバーは落としておくべきです。
 上記の例だと、その本番環境と同等にしていた場合には、19時に帰宅して翌日の10時に出社するだけでも1350$掛かりますからね! もし金曜に立ち上げっぱなしにしてしまった場合、月曜に気付いた時にはお給料以上のお金が吹っ飛んでいますね! とっても怖いですね!
 そんな事で、負荷試験環境はスクラップ&ビルドが簡単な状態にしておく事が望ましいです。……とても大変ですけど。

 また、本番想定の為、DBの負荷を正常に測る為に想定ユーザー分のダミーデータをDBに突っ込んでおく必要もあります。
 これに関しては、最初にリセマラを想定した負荷試験をすれば行う必要も無くなる事もありますが、スクリプト等を別途組んでおけば楽になるでしょう。

環境の立ち上げが一向に上手くいかないエンジニア

負荷試験スタート

 さて。
 ここまで整えて、やっと負荷試験はスタートを迎える事が出来ます。
 上記の通り、スタートを迎える為に準備する事柄は数多にありますので、負荷試験フェーズに入ってからの一からの準備ではもう手遅れ、残業塗れになる事は想像に難くありません。
 そんな事にならない為にも、開発フェーズから負荷試験の事は考えておく事をお勧めします。

*****

「よし! 単体サーバーで150RPSまで捌けるようにコードの改善も出来たぞ! 性能が1.5倍! コストは2/3! ダミーデータもたっぷり入れたし、これからサーバー台数を一気に増やして本番想定の負荷試験だ!」
「すまん、リリース前だが仕様変更だ」
「えっ、ちょっと、この仕様テーブル定義かなり変わるじゃん、土日掛けて突っ込んだ膨大なダミーデータ無駄じゃん」
「すまんが頼むね」
「…………」
 頑張りましょう。

駄々をこねるエンジニア

え、まだ健康診断うけてないの?って言われない方法

0

はじめに

「健康診断受けてね!!」
「まだ予約してないの!!?」

年末になると健康診断担当から沢山届く通知……
アピリッツ年末の恒例といっても過言ではないはず……
(恒例化したくない;;)

正直、健康診断メンドクサイと思っている人、いると思います。

と、いうことで
どうして健康診断ってうけなきゃいけないの?
どんなメリットがあるの???
について、健康診断担当者がわかりやすくお伝えしていきたいと思います!

これを読めば、来年からは「え、まだ健康診断うけてないの?」って言われなくなるはず…です!

どうして健康診断をうけなきゃいけないの?

★そもそも法律で決められている!!

健康診断の受診は、労働安全衛生法第66条で定められた義務です。

出典:労働安全衛生法 第66条

企業の義務
「事業者は、労働者に対し、厚生労働省令で定めるところにより、医師による健康診断(中略)を行わなければならない。」

労働者の義務
労働者は(中略)事業者が行なう健康診断を受けなければならない。


健康診断を行うことは「企業(アピリッツ)と労働者(アピリッツで働く人)それぞれの義務」で、受診させない・受診しないことは法律違反になってしまうのです…!なので健康診断担当者は「健康診断、受けてね!!」と連絡を沢山しているワケなんですね。ふむふむ。

毎年健康診断を受けていれば、カラダの経年変化に気づけるし、病気を早期に発見することもできるかもしれません。(事実、社員の中には、健康診断のおかげで初期で病気を発見できた方も……!)

しかもアピリッツでは会社で初回の健康診断費用を負担してくれる!

自己負担無しで自分について知れる……しかも婦人科検診オプションも1個自己負担なしで付けられる……だと? え、すごくない?|д゚)

ふーん、なるほど。
健康診断はやっぱり受けなきゃなのね~~

その通りです、アピ子さん。だんだん健康診断受けたくなってきましたか?(笑) ここでさらにすごいポイント!

ここがすごいよ!アピリッツの健康診断!

★MY HEALTH WEBで、健診結果がまとめて見れるらしい

MY HEALTH WEBとは、アピリッツが加入している関東ITソフトウェア健康保険組合の個人向け健康ポータルサイトで、アピリッツで健康保険に加入している人であれば皆さん使えるものです。ポイントでアイテム交換できたり、医療費通知の閲覧ができたり色々便利なサイトのようですが、健診結果の閲覧もできる!

提携している病院であれば、どの健診期間で受診したものでも一元管理できるとのこと!

これで「結果をまとめて見れるから、いつもの病院で予約したいけど予約いっぱいで健康診断受けられません………」なんて問題もクリアですね!! ※MY HEALTH WEBの詳細はこちら

★会社内で健康診断受けられる

「わざわざ病院に行くのめんどくさいな」という声にお答えして、年に1度病院を会社に呼んで会社で健康診断を受けられるようにしています!(2020年度はコロナ感染防止のため中止)

★業務扱いになる

実は、健康診断の時間って労働基準法によると労働時間ではないのです! でも、アピリッツでは平日に受けた健康診断の時間は業務扱い(労働時間としてカウント)となっています。業務扱いになりますので、皆さんきちんと健康診断受けてくださいね★

健康診断の重要性はわかりましたよ、でも早めに受けなくてもいいのでは?

いやいや、ちょっとまってくださいなアピ子さん。

早く受ける(予約)すると何がいい??

★余裕を持って受けられる

12月までとかに受けとけばいいや~と思っている人はご注意を! 年末は駆け込み予約が多いです。「ギリギリに受けようと思ったら、行きたいところが予約いっぱい!家から遠い所で受けなきゃ;;」みたいにならないように余裕をもって予約しましょう! 健康診断担当から、せかされることもなくなります(笑)

★健康診断担当者、嬉しい^^

実は健康診断担当者が、健康診断の受診状況を労働基準監督署に提出しています! 早めに予約・受診してもらえると、余裕をもって受診状況を報告できるので担当者、嬉しい。(喜びかみしめる) 年末に今年度もちゃんと法律を守れるか、ドキドキする必要もありませんね^^

ほうほう、ということは
健康診断の案内が来た時点で先に予約しちゃえば

「え、まだ健康診断うけてないの?」って言われない?

はい大正解ヾ(≧▽≦)ノ! 健康診断はお早めにお願いします★(予約だけでもいいから……はやめに対応……!懇願)

「5年後、10年後のキャリアだけじゃなく、30年後も考えよう」メディアサービス部 部長 鈴木利夫 インタビュー

0

メディアサービス部(以下、MS部) 部長 鈴木利夫さんのインタビューです。「5年後だけじゃなく30年後のキャリアを面接で訊くのは、本気で考えてほしいからですよ」と語る鈴木さんに、部のこと、そして採用面接のことを中心に話を聞きました。(2020年12月 取材)

鈴木 利夫
メディアサービス部 部長
2011年 入社
映画を観ることが好き。最近すごかった映画は『KILLER SOFA』。

メディアサービス部は「職人」が多い部署

―― アピリッツご入社の経緯を教えてください

詳しくは言えないのですが、もともとは通信系の研究機関に長く関わっていました。そこで新しい通信サービスの仕様を作ったり、自分でプログラムを書いたり、開発会社に発注したり。

―― つまり元々はエンジニアだったのでしょうか?

“開発現場よりのプロジェクトマネージャー”がより適切な職種だったと思います。複数のプロジェクトに同時に参加して、過去の経験値をもとに「そもそもこういう要件でしたよね?」「ここ直したほうがよくないですか?」などと相談するんです。

自分で開発することもあれば、開発を別の会社にお願いすることもありましたし、いろんなレイヤーの仕事に関わって、管理や調整ごとを引き受けていました。

で、いろいろあって、知人の紹介でアピリッツに参加しました。

―― メディアサービス部はどういうチームですか?

私達はメディアに関連したサービスやWeb全般の仕事はなんでもやります。で、MSは「ザ・職人!」といった感じのチームです。技術を深堀りしていく人が多いですね。他の部署と連携しながら仕事をするメンバーもいます。

―― 鈴木さんは、どういうふうにMS部を率いていますか?

(しばらく腕を組んで考えたのち)あまり口を出さないようにしています。自分たちで考える力を身につけてほしいからです。“自走力”ってよく言われる言葉ですよね。自走するためには、経験するしかありません。ですから、口は出さずに見守っています。

這い上がる根性を持っている人は伸びる

―― どんな人が伸びていると感じますか?

「伸びる=技術力を高めること」だとするなら、身もふたもないことを言いますと、「伸びたい」と思って動けるひとが伸びます。

もちろん、伸びないひとだって何も考えていないわけじゃなく、「まずいな」「置いていかれるな」と認識しているはずです。でも「どうやったら追いつくのか」「どう動けばいいのか?」を考えて動けない。

こういうことって、他人に教わったからどうにかなるものでもないと考えています。誰かの話を聞いたり、本を沢山読んだからって、よいコードが書けるわけないんです。ラーメン1000杯食べたってラーメン屋にはなれないのと同じ。ラーメン屋になりたいんだったらラーメンを作る以外ないです。

だから、コードも書かないとうまくなりませんし、自分でやらないとできないんです。

自分の場合、若いとき最初に就いた仕事って、製造する会社さん向けに仕様を作ることだったんです。で、上司に見せると「ダメ」とだけ言われる。ひたすら直して提出して、また「ダメ」って言われて、また直して……「どこがダメなんだ?」って当然ムカつきますよ。で、ムカつくから「次こそは!」って頑張る。

最後にやっと受け取ってもらえたんですが、そのときも一言「センスねえな」って(笑)。やっぱりムカつく!(笑)で、「次はもっと良くしてやる!」って燃えるんです 。こんなやりかたが今の時代と合ってるかは、はなはだ疑問です。ただ、這い上がる根性を持ってる人は必ず大きく成長します。

話すと優しい鈴木さん。(撮影のためにマスクを外しています)

―― では、どんな人に来てもらいたいですか?

職人も必要ですが、同時に、職人ではない方も必要だと思っています。たとえば、昨今話題になっているDX(デジタルトランスフォーメーション)推進をおこなう場合、DXマネージャーは必須の存在です。

もしDXマネージャーがいないままプロジェクトが始まると、「DXを技術で解消しましょう」と動く実行部隊だけで終わってしまうんです。「どういう技術で、こんなDXを実現しましょう」というお話を、お客様と会話できる人が必要です。

私達は「ものを作る」ことを中心とする人が多い組織ですから、これから先は”旗振り役”な方にも今よりもっと沢山来ていただいて、よりスケールアップしていきたいです。

「5年後のキャリアはわかったよ。じゃあ、20年後、30年後どうしてたい?」

―― 鈴木さんは採用面接でどういうところを気にしますか?

その方の立ち位置によって視点を変えています。

中途採用の場合は、それまでのお仕事と、当社でやりたいことを伺って「じゃあ、この人は本当にアピリッツで長く働いていただけるか?」と考えます。スペシャリストを志向する人ならば、もちろん技術を重視します。

第二新卒の場合は、面接の時点での技術の高さは問いません。自分の将来を考えているかどうか、また、自分のレベル感をどのように把握されているかをよく質問します。

「チームを率いたい」と志望する人が、いざ現場に入ったら自分よりはるかに技術が高い”ザ・職人”たちの集団が待ち構えているわけですから、そりゃ大変です。そのあたりのギャップや覚悟がどのくらいあるかを冷静に話し合うことが大事だと思います。あと、夢も希望もなく入っても成長はむずかしいですし、楽しくないですから、何をしたいのかは知りたいですね。

最近はプログラミングスクール出身者もアピリッツに入社してくれています。彼らは勉強熱心で根性があります。ですから、これから大きく伸びていくだろうなと感じています。

最後に、新卒。新卒はいろんな方が応募してくださるので、会社的に合っていそうか、技術に興味があるかを重視します。そうじゃないと仕事はつらくなるでしょうし、本人もつらいですからね。

―― 最近入ったプログラミングスクール出身者の方が、採用面接時に「5年後、10年後のキャリア像は?」に加えて「じゃあ、20年、30年後は?」と鈴木さんに質問されてびっくりしたと聞きました。

あれね、冗談めかして質問していますが、30年後をどう思っているかはホントに知りたいし、考えてほしいんですよ。だから同じことを部のメンバーにも必ず訊いています。定年を迎える頃に何をしてたい? コードを書いてると本気で思っている? それって結構しんどくないですか? じゃあどうする? って。

―― では、鈴木さんは定年頃に何をしていたいですか?

そりゃもう、気持ちよくスパッと仕事を辞めたい(笑) 仕事を続けるなら、コンサルをやります。

―― ありがとうございました! インタビューの前に「俺の話なんてあんまりおもしろくないよ~」っておっしゃってましたが、おもしろかったです

そう? 書けない話ばっかりじゃなかった? 「ここだけの話」ってのも色々あるので、それはみなさん直接聞きにきてください(笑)

関連記事:アピリッツのその他の役員インタビュー

【IE11対応】背景画像のsvgを自由に色変えしたい

0
いろいろな矢印
矢印はたくさん使います

デジタルビジネス部所属Webデザイナーの黒須です。

SCSSを利用して、CSS(background-image)にSVGファイルを指定し、SVGらしくアイコンの色変えをサッと実現する方法を紹介します。

第一章 
SVGファイルそのものを整えてから

色変えするしないにかかわらず、SVGファイルの中身を理解し、気を配りましょう。

1.  SVGファイルを最適化

見た目は問題がなさそうなSVGファイル…
しかし

  • 隠れた不要なレイヤー
  • 要らない空パス
  • パスが閉じていない

など、データとして問題がないかチェックします。

Illustratorで作業

  1. 不要な隠しレイヤーなどを全て削除
  2. パスをアウトライン化
  3. 同じ色は複合パスでまとめる(cmd + 8)

複合パスの必要性

同じ色(fill1つで指定)のパスは1つにまとめます。
また複合パスでまとめることでデータを軽量化できます。
必要な物だけ残しシンプルでわかりやすいデータを目指します。

例えばこのような2つの>の字でデザインされた矢印アイコンは、複合パスにできます。

複合パスにせずそのまま書き出した場合、
SVGの中身(テキストデータ)はこんな感じ ※テキストエディタで開く

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 492 492" style="enable-background:new 0 0 492 492;" xml:space="preserve">
<g><polygon points="69.8,0 0,69.8 176.2,246 0,422.2 69.8,492 315.8,246"/></g>
<g><polygon points="246,0 176.2,69.8 352.4,246 176.2,422.2 246,492 492,246"/></g>
</svg>

<g></g>が2つで、>の字パスが2つ描かれていることがわかります。

複合パスにした場合

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"viewBox="0 0 492 492" style="enable-background:new 0 0 492 492;" xml:space="preserve">
<path d="M69.8,0L0,69.8L176.2,246L0,422.2L69.8,492l246-246L69.8,0z M246,0l-69.8,69.8L352.4,246L176.2,422.2L246,492l246-246L246,0z"/>
</svg>

パスが1つになりました。
この1つのパスに対して、fillでカラー指定すれば一発で色が変えることができます。
(パスが複数ある場合それぞれfillを記述しなければならないため余計な手間が増えます)

なおここまでの作業は、コーディングに渡す時点で完了していることが望ましいです。
隠れたレイヤーやパスが本当に要らないものかジャッジするのは作成者(デザイナー)の仕事です。
完成したファイルを次の工程(コーディング)に渡しましょう!
色変えを前提に作成している…などデザイン時に考慮している部分もしっかり共有しましょう。

2. SVGOMGでさらにダイエット

Adobe系・FigmaなどアプリからSVGを書き出した状態では、Web掲載時には必要ない記述が含まれているため、削除してファイルサイズを軽減します。
https://jakearchibald.github.io/svgomg/
ありがたい「SVGOMG」というWebサービスに、サッと湯通しします。
初期設定でひとまず問題ありません。

llustratorで書き出したままのファイル

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 563.56 543.71">
 <g id="レイヤー_1" data-name="レイヤー 1">
  <g id="Layer_1" data-name="Layer 1">
   <path d="M77.14,0,0,77.14,194.72,271.86,0,466.58l77.14,77.13L349,271.86ZM291.7,0,214.56,77.14,409.28,271.86,214.56,466.58l77.14,77.13L563.56,271.86Z"/>
  </g>
 </g>
</svg>

SVGOMGを通したファイル

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 563.56 543.71">
  <g data-name="レイヤー 1">
    <path d="M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z" data-name="Layer 1"/>
  </g>
</svg>

すっきりしました。
もっと複雑なファイルであればその効果は歴然です!

3. エディタでソースを確認する

SVGOMGしたファイルに問題がないか、まず確認します。

中身を理解する必要がありますし、この一手間の積み重ねが美しいサイトを作ります。
datan-name<g></g>、id・height・widthなど、使用する明確な予定が無ければ削除します。
(ie11で表示が豆粒になるバグが発生した場合はwidth/heigthを入れると解決するパターンがあるため適宜残してもよいです)

シンプルなSVG 理想の形

<svg xmlns="http://www.w3.org/2000/svg" viewBox="〇〇〇〇">
  <path d="〇〇〇〇"/>
</svg>

この形を目指します。
エディタでファイルを開き、余計な部分を削除します。

最終的なファイル

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 563.56 543.71">
  <path d="M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z"/>
</svg>

シンプルで気持ちがいいです。
これでSVGファイルの準備ができました。

第二章 
いよいよコーディング SCSSでパターン作成

SCSSで簡単にコーディングするために、mixinを作成し使いまわします。
ひとまず完成形はこちらです。

SCSSでの使い方

.btn-A {
  @include svg-arrow(re-color($white));
}

.btn-B {
  @include svg-arrow(000);
}

$white(サイトカラーを格納している変数)や、000(カラーコード)を指定し、その色のSVGを呼び出している感じがありますね。

CSSコンパイル結果

.btn-A {
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath fill='%23ffffff' d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E") 50% 50%/100% 100% no-repeat;
}

コンパイルすると、この面倒なSVGデータを自動で書き出してくれます。
fill=’%23ffffff’(fill=#fff) 白のカラーコードがちゃんと入っています。

では、このmixinの作り方、具体的に何をしているのか解説します。

1. テンプレートとなるmixinを定義する

mixinテンプレート

@mixin svg-〇〇() {
  background: url("data:image/svg+xml;charset=utf8,△△")
  50% 50% / 100% 100% no-repeat;
}

mixinはこんな感じです。↑コード内の

〇〇 = mixinに好きな名前をつける(接頭語を「svg-」とするmyルール策定)
△△ = SVGのテキストデータを記述する(次の項目で詳しく解説します)

このmixinを複製し、アイコンのストックを作っていくイメージです。

2. URLエンコード(IEのため)

SVGのテキストデータはそのままではIEが理解できないので、URLエンコードします。
https://yoksel.github.io/url-encoder/
※シングルクウォーテーションにする必要があります
(エンコーダーが一緒にやってくれます便利〜)
※SVGファイルをエディタで開いてください

SVGテキストデータを

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 563.56 543.71">
 <path d="M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z"/>
</svg>

エンコードすると、こうなります

%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E


3. テンプレートに挿入

エンコードしたSVGのテキストデータを、テンプレート「△△」部分に挿入します

@mixin svg-arrow() {
  background: url("data:image/svg+xml;charset=utf8,△△")
  50% 50% / 100% 100% no-repeat;
}
@mixin svg-arrow() {
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E")
  50% 50% / 100% 100% no-repeat;
}

色を指定する「fillの指定」を path と d=”〜” の間あたりに追加します。

@mixin svg-arrow() {
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath fill='%23ffffff' d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E")
  50% 50% / 100% 100% no-repeat;
}

fillの指定

fill='%23ffffff'

#ffffffを直接指定しています。
「#」もエンコードする必要があるので「%23」にします。

これで、白色の矢印アイコンのmixin「svg-arrow()」ができました。
さらに、色の変更を簡単するため、ひと工夫します。

4.  fillを変数にして、気軽に色変える

@mixin svg-arrow($color: 000) {
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath fill='%23#{$color}' d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E")
  50% 50% / 100% 100% no-repeat;
}

変数を定義し、svg-arrow($color: 000)  例:000をデフォルトに定義

// Before
@mixin svg-arrow() { 〜 }

// After
@mixin svg-arrow($color: 000) { 〜 }

mixinの中で受け取っています。fill=’%23#{$color}’

// Before
fill='%23ffffff'

// After
fill='%23#{$color}'

使用するときは、

.btn-B {
  @include svg-arrow(fff);
}

違う色の指定が簡単です。

5. サイトカラーを変数で管理している場合

@include svg-arrow($red);

このように、変数で管理しているカラーを使いたいですね。
しかし、このままではコンパイルエラーになります。

変数の中身次第ですが、カラーコード用の「#」が入っているため問題が起こります。

$red: #e94527;

したがって、データ的に「#」を削除するfunctionを作成し、正しい形に直せば利用できます。

カラーコード#抜き関数

@function re-color($code) {
  @return str-slice("#{$code}", 2);
}

カラーコード入りの変数を使いたいときは、この「#抜き関数」で補完する感じです

//変数
.btn-A {
  @include svg-arrow(re-color($red));
}

//カラーコード #付きの場合
.btn-B {
  @include svg-arrow(re-color(#fff));
}

//カラーコード数値のみなら、re-color不要
.btn-C {
  @include svg-arrow(fdfdfd));
}

カラー「$red」を指定して、SVGを呼び出すことができました。

また、アイコンの初期カラーは全て変数の「$main」カラーにするmyルールを定めた場合、
mixin側にも「#抜き関数」を使用します。

@mixin svg-arrow($color:re-color($main)) {
  background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 563.56 543.71'%3E%3Cpath fill='%23#{$color}' d='M77.14 0L0 77.14l194.72 194.72L0 466.58l77.14 77.13L349 271.86zM291.7 0l-77.14 77.14 194.72 194.72-194.72 194.72 77.14 77.13 271.86-271.85z'/%3E%3C/svg%3E")
  50% 50% / 100% 100% no-repeat;
}

最後に

SVGの色パターンをCSSだけで増殖させる方法でした。
簡単………しっかり解説すると長くなってしまいました。

サイトの規模・パターン数によってこれがベストではないことをすでに感じていますが、何かお役に立てたらハッピーです。

ベイズ統計学の世界への誘い

0

はじめに

データイノベーション部の浅田です。

統計学のひとつにベイズ統計学というものがあります。ベイズ統計学は現代の機械学習において、重要な一角を占めています。

例えば、スパムメールかどうかを判定する機械学習の手法にナイーブベイズという手法があります。これはメールの文面に記載される単語について、スパムメールにその単語が出現する確率を学習しておき、判定対象のメールに書かれた単語から、そのメールがスパムメールかどうかを判定するような仕組みになっています。その際に、ベイズ統計学の根本をなすベイズの定理が使われています。

また、機械学習においては、パラメータの最適値を探す作業が度々発生します。例えば、ハイパーパラメータと呼ばれる人間が指定しなければいけない値がありますが、その値の最適値を探索する必要があったりします。そのような場合に、取りうるすべての値を試すのは時間がかかるので、効率的に探索する必要があります。そのような時に最適解に導く手法の一つに、ベイズ最適化というものがあり、その名の通りベイズ統計学の仕組みが使われています。

このように、機械学習についても重要なファクターであるベイズ統計学の理論についてご紹介したいと思います。

ベイズ統計学

ベイズ統計学では、確率は事象における直観的信頼度として表現されます。「事象の直観的信頼度」を平たい表現にすると、事象が起こると信じる度合い、と言えます。ベイズ的な考え方においては、信じる度合いとしての確率はデータ(確認された事実)によって変動します。その更新はベイズの定理によってなされるため、ベイズ更新と呼ばれます。

ベイズの定理

ベイズの定理は以下のような式になります。

\begin{aligned}P(H \mid D ) = \frac {P(D \mid H) \times P(H)}{P(D)} \end{aligned}

要素を分解してみましょう。$P$という記号は確率を表します。$P(H)$は$H$という事象が起こる確率と言う意味です。例えば、「真っ当な」サイコロであれば1が出る確率は$\frac{1}{6}$となるので、

\begin{aligned}P(サイコロで1が出る) = \frac{1}{6}\end{aligned}

となります。

$P(H \mid D)$は、条件つき確率と呼ばれるもので、$D$という条件が満たされた場合に$H$が起こる確率となります。

例えば、「真っ当な」サイコロで1が出る確率は先ほどの通り$\frac{1}{6}$となりますが、そこにサイコロの目が奇数だった、というデータ($D$)があらかじめ観測されたとします。そうすると、その条件の際に1になる確率は1,3,5のどれかに絞られるので、$\frac{1}{3}$となります。

つまり、

\begin{aligned}P(サイコロで1が出る \mid 出目が奇数) = \frac{1}{3}\end{aligned}

ということですね。

これをベイズの定理に当てはめてみましょう。

\begin{aligned} P(サイコロで1が出る \mid 出目が奇数 ) &=\frac {P(出目が奇数 \mid サイコロで1が出る) \times P(サイコロで1が出る)}{P(出目が奇数)}\\ &=\frac {1 \times \frac{1}{6}}{\frac{1}{2}}\\ &=\frac {1}{3} \end{aligned}

これは、ベイズ的な解釈をすれば「出目が決まっていない状態でサイコロの1の目が出ると信じていている確率である$\frac{1}{6}$が、出目が奇数であるという新たなデータを得たことで$\frac{1}{3}$に更新された(確信度があがった)」ということになります。これがベイズ更新の流れになります。

これだけだと回りくどいことをやっているように感じるかもしれませんが、ベイズの枠組みの面白いところは、この枠組みを主観的なパターンに応用できるところです。

イカサマサイコロ?

例えば、先ほどから「真っ当な」サイコロと表現していましたが、もし5回投げて5回とも1が出るという事実を目にした場合、このサイコロを真っ当なサイコロと思うでしょうか?5回も1が出たら「なにか変だぞ?」と思うのではないでしょうか。

その時の確信度の変化をベイズの定理でモデル化してみます。

\begin{aligned} P(イカサマ \mid 5回連続1が出る ) &=\frac {P(5回連続1が出る \mid イカサマ) \times P(イカサマ)}{P(5回連続1が出る)} \end{aligned}

この時、ベイズ統計では、

  • $P(イカサマ \mid 5回連続1が出る )$を事後確率
  • $P(5回連続1が出る \mid イカサマ)$を尤度(ゆうど)
  • $P(イカサマ)$を事前確率
  • $P(5回連続1が出る)$を周辺尤度

と表現します。

事前確率、事後確率、尤度、周辺尤度

ベイズの定理の再掲となりますが、

\begin{aligned}P(H \mid D ) = \frac {P(D \mid H) \times P(H)}{P(D)} \end{aligned}

ベイズ更新においては、上記の$P(H \mid D)$は「$D$という事象(データ)が観測された事後にHという事象が起こる確信度」となり、$P(H)$は「$D$という事象(データ)が観測されるよりも事前に$H$という事象が起こる確信度」となります。そのため、$P(H \mid D)$を事後確率、$P(H)$を事前確率と呼びます。ベイズ更新の枠組みでは、この事前確率を主観で決めてしまって構いません。なので、人間が事前知識として持っている確信度を当てはめてしまって問題ありません。データを観測することで、事前確率はデータを反映した事後確率に更新されることになります。

なお、ここまで$H$という文字を使っていましたが、これはHypothesis(仮説)の頭文字を表しています。事象$H$が起こる確信度とは、言い換えれば、事象$H$が起こるという仮説を信じる度合いと見なせます。つまりベイズ更新とは、観測されたデータによって仮説に対する確信度がどう更新されるか、ということをモデル化しているということになります。

事前確率がどのように事後確率に更新されるかは、$P(D\mid H)$と$P(D)$の比である$\frac {P(D\mid H)}{P(D)}$によって決まります。分子の$P(D \mid H)$を尤度(ゆうど)と呼びます。仮説$H$が正しいとした時にデータ$D$が観測される尤もらしさ、つまり「データが持つ仮説$H$に対する説得力」を表します。分母の$P(D)$は「データが一般的に観測される確率」で、周辺尤度などと呼ばれます。

$\frac {P(D\mid H)}{P(D)}$という値は$P(D \mid H)$が$P(D)$に比べて大きければ大きいほど値は大きくなります。言い換えると、データ$D$が一般的に観測される確率よりも事象$H$が起きた時にデータ$D$が観測される確率が高い事象であればあるほど大きくなります。したがって、観測されたデータ$D$が仮説$H$に対して固有であればあるほど、事前確率は確信度の高い事後確率に更新されることになります。

例えば、先ほどのイカサマサイコロの例であれば、5回連続1が出ることは真っ当なサイコロではレアケース=一般的にありえないであるため、イカサマがある時のほうが観測される確率が高いと判断されます。その結果、「イカサマサイコロかも」という思いはより確信度が高くなるでしょう。

続・イカサマサイコロ?

ベイズ統計モデリング

先ほどの5回連続で1が出た際に、「イカサマがあるんじゃないか?」と主観が変化することをベイズ統計を使ってモデリングしてみます。

今回は、

仮説$H$ =「サイコロで1が出る確率が6回に1回である」

とします。事前確率$P(H)$は仮説$H$に対する確信度ということになります。さて、その確信度をどう定義するかですが、ベイズ統計モデリングの特徴として、事前確率や事後確率を定義する際に確率分布を用いる点があります。

確率分布を用いることで、確率をより直観的に表現できます。

その確率分布に、α回成功してβ回失敗したときに、その成功確率pの分布を表現できるベータ分布というものがあります。

式の定義としては、

\begin{aligned} f(p;α,β) &=\frac {p^{α-1}(1-p)^{β-1}}{\int_0^1t^{α-1}(1-t)^{β-1}dt} \end{aligned}

となります。例えばα=5, β=5を指定すると、5回成功して5回失敗する場合の統計的な成功率の分布を表現することができます。式だけだと何ぞやって感じだと思いますので、ベータ分布をいくつか図示してみます。

上図のように、α=5, B=5であれば成功率0.5付近が確信度が一番高くなっている形状になり、α=3, β=7だと成功率0.3付近が一番確信度が高くなっています。このようにして信頼度の分布を表現できるのが、確率分布を利用することによるメリットの一つです。なお、合計が10である必要はなく、任意の1以上の整数の組み合わせを指定できます。

ちなみに、α=5, β=5、α=10, β=10を指定した場合、成功率の確信度が高くなるのは0.5付近で同じですが、形状が少し異なります。

これはα=10, β=10のほうが「成功率が0.5付近であること」をより確信していることを表しています。なので、αとβの比は同じでも、合計数が大きくなればなるほど、成功率に対してより確信度が高い状態となります。これはデータが多ければ多いほど、真の値に近くという統計学の基本定理大数の法則とも合致します。

今回はこのベータ分布を事前確率として用います。今回のケースでは1が出ることを成功として定義して、1以外が出ることを失敗として定義すると、サイコロで6回に1が出る確率の分布を表現できます。今回は6回に1回ぐらい成功するはずだということで、α=2, β=10(12回投げて、2回は1が出て、10回はそれ以外が出る)としておきましょう。

なので事前分布$P(H)$は、以下のようになります。

\begin{aligned} f(p;2,10) &=\frac {p^{2-1}(1-p)^{10-1}}{\int_0^1t^{2-1}(1-t)^{10-1}dt} = \frac {p(1-p)^{9}}{\int_0^1t(1-t)^{9}dt} \end{aligned}

次に尤度です。尤度は仮説が正しいとした場合に、データが得られる確率です。つまり今回の場合、成功確率が6回に1回だったとして、5回中5回とも1の目が出る確率になります。このような時に使える分布として二項分布というものがあります。

\begin{aligned} f(k;n,p)=_n C _k p^k(1-p)^{n-k}=\frac{n!}{k!(n-k)!}p^k(1-p)^{n-k} \end{aligned}

この式で、kは成功回数、nは試行回数、pは成功確率となります。成功確率がpの時に、5回中5回成功する確率は、上記式に当てはめれば、

\begin{aligned} f(5;5,p)=\frac{5!}{5!(5-5)!}p^5(1-p)^{5-5}=p^5 \end{aligned}

となります。したがって$p^5$が今回の尤度です。

最後に、周辺尤度です。周辺尤度は尤度と事前確率分布との積であらわされる関数について全ての確率変数pを入力とした時の出力の合計値として算出されます。従って、事前確率分布の確率変数が取り得る値である0から1で関数を積分した値となります。

つまり、周辺尤度を式で表すと以下のようになります。

\begin{aligned} \int_0^1\frac {p(1-p)^{9}p^5}{\int_0^1t(1-t)^{9}dt}dp = \int_0^1\frac {p^{6}(1-p)^{9}}{\int_0^1t(1-t)^{9}dt}dp \end{aligned}

したがって求めるべき事後分布である$P(H \mid D)$は

\begin{aligned}P(H \mid D) =\frac {\frac {p^{6}(1-p)^{9}}{\int_0^1t(1-t)^{9}dt}}{\int_0^1\frac {p^{6}(1-p)^{9}}{\int_0^1t(1-t)^{9}dt}dp}\end{aligned}

…(´・ω・`)

こんなの手で計算したくないですよね(少なくとも自分はやりたくありません)。ということで、python先輩にお任せします。

ここまでの計算をpythonのコードに落とし込むと、

import scipy.integrate as integrate


# 事前確率分布
p_h = lambda p: p * (1-p) ** 9 / integrate.quad(lambda t: t * (1-t) ** 9, 0, 1)[0]
# 尤度
p_d_h = lambda p: p ** 5
# 周辺尤度
p_d = integrate.quad(lambda p: p_d_h(p) * p_h(p), 0, 1)[0]
# 事後確率分布
p_h_d = lambda p: p_d_h(p) * p_h(p) / p_d

scipy.integrate.quad()は、第一引数の関数を、第二引数から第三引数の区間で積分してくれる関数です。結果は積分結果と誤差とのtapleになっています。なので、[0]を指定することで積分結果を取り出しています。

これで事後確率の確率分布が求まりました。事前確率の確率分布と尤度とともに図示して見ましょう。

import matplotlib.pyplot as plt
import numpy as np


# 確率変数
p = np.arange(0, 1.01, 0.01)
# グラフの準備
fig = plt.figure()
ax = fig.add_subplot(111)
plt.title("ベイズ更新")
plt.xlabel("成功率")
plt.ylabel("確信度")
# 事前確率分布
plt.plot(p, p_h(p), 'k--', color='g', label="事前確率")
# 事後確率分布
plt.plot(p, p_h_d(p), color='b', label="事後確率")
# 凡例
plt.legend(loc='lower right', borderaxespad=1, fontsize=12)
ax.twinx()
plt.ylabel("尤度")
# 尤度
plt.plot(p, p_d_h(p), 'k--', color='r', label="尤度")
# 凡例
plt.legend(loc='upper right', borderaxespad=1, fontsize=12)

緑の破線で描かれている事前確率分布は0.15付近、つまりおよそ$\frac{1}{6}$付近の確信度が高くなっているのが見て取れます。これはデータを観測する前には、真っ当なサイコロで1が出る確率である$\frac{1}{6}$付近がサイコロで1の目が出る成功率だと信じていたことを示しています。

そして、赤の破線が尤度です。$\frac{1}{6}$付近の尤度は極めて低くなっています。ほぼ0です。これは5回連続で1の目が出ることは、1の目で出る成功率が$\frac{1}{6}$だとしたら、ほとんどありえないことを表します。

ベイズ更新の結果である、青の実線で描かれた事後確率分布では、成功率$\frac{1}{6}$付近の確信度はかなり下がっています。その代わり事前確率分布ではかなり確信度が低かった0.4以上の成功率に対する確信度が上がっています。つまり、データを観測した結果、成功率は$\frac{1}{6}$付近ではなく、もっと高い成功率なのでは?と考えるようになったことを表しています。

なお、今回のように確率分布における確率変数(今回の場合は成功率)が連続値である場合には、確率分布の関数を確率密度関数と言います。一方、二項分布などの場合には、確率変数が離散値となるので確率質量関数などと言います。確率密度関数においては、確率変数の値で積分をおこなうことによって、特定の確率変数の範囲における確率を計算することができます。例えば、今回のケースで言えば、サイコロの1の目が出る確率が0.4以上である確信度を計算することができます。

# 事前確率の0.4以上の成功率に対する確信度
print(integrate.quad(p_h, 0.4, 1)[0]) # 0.030233088000000016
# 事後確率の0.4以上の成功率に対する確信度
print(integrate.quad(p_h_d, 0.4, 1)[0]) # 0.5271741135912963

上記の結果から、0.4以上であることの確信度は0.03(=3%)から0.53(=53%)に跳ね上がったということになります。このようにピンポイントの確率変数だけでなく範囲を指定した確率変数に対する確信度を計算しやすい、というのも確率分布を使うメリットですね。

別解:scipy.statsにある確率分布を利用する

さて、上記では確率分布の定義式に、パラメータを当てはめて計算結果を求めたわけですが、pythonのscipyライブラリにあるstatsモジュールには様々な確率分布の計算を楽にしてくれる関数があります。

それを使うと先ほどの事後確率の計算は以下のようにも書けます。

import scipy.stats as st
import scipy.integrate as integrate


# 事前確率分布
p_h = lambda p: st.beta.pdf(p, a=2, b=10)
# 尤度
p_d_h = lambda p: st.binom.pmf(p=p, n=5, k=5)
# 周辺尤度
p_d = integrate.quad(lambda p: p_d_h(p) * p_h(p), 0, 1)[0]
# 事後確率分布
p_h_d = lambda p: p_d_h(p) * p_h(p) / p_d

scipy.stats.betaはベータ分布、scipy.stats.binomは二項分布を表します。beta.pdf()はベータ分布の確率密度関数を計算してくれる関数、binom.pmf()は二項分布の確率質量変数を計算してくれる関数になります。

上記の事前確率分布と尤度に使う組み合わせを変えてやれば、様々な確率分布を利用したベイズ更新に応用できます。

さらに別解:ベータ分布の性質の利用

なお、今回事前分布に利用したベータ分布は、尤度につかった二項分布と組み合わせた場合に、事後確率分布もベータ分布になります。尤度に対して、事前と事後の確率分布の種類が同じになる事前確率分布を共役事前分布と言ったりします。

そして、ベータ分布には便利な性質がもう一つあります。

それは、事前確率分布にベータ分布を使った場合、尤度にn回中k回成功した二項分布を使って事後確率分布を計算した結果と、事前確率分布のパラメータα, βに、それぞれ成功回数、失敗回数を追加したパラメータα+k, β+n-kを使って計算したベータ分布の結果とは一致するという性質です。

つまり、わざわざ二項分布をつかって尤度を計算したり、積分を行って周辺尤度を計算せずとも、事前確率分布のパラメータを調整するだけで、事後確率分布を得ることができます。

すなわち、今回のケースで求めた事後確率分布は以下のようにも求められます。

import scipy.stats as st


# 事前確率分布はα=2, β=10であり、
# 5回成功し、0回失敗したデータを観測したので
# αに2+5+7、βに10+0=10を指定する。
p_h_d = lambda p: st.beta.pdf(p, a=2+5, b=10+0)

事後確率分布は次のベイズ更新の事前分布として利用できる

以上でベイズ更新を使ってデータを観測した事後確率分布を求めることができました。そして、この事後確率分布はさらなるデータが観測された時の事前確率分布として使用できます。

つまり、さらにサイコロを振ったときにn回中k回1が出たデータを観測したのであれば、

import scipy.stats as st


p_h_d = lambda p: st.beta.pdf(p, a=7+k, b=10+n-k)

でさらなる事後確率分布を求められます。そのようにしてどんどんデータを集めていけば、その確信度を示す確率分布の密度は真の値付近に集中していきます。密度が集中している、つまり確信度が高いということは、データから判断するとその付近が求めたい値だと判断できるということです。

それがおよそ$\frac{1}{6}$に近づけば、そのサイコロは真っ当なサイコロであると判断できるでしょうし、それ以外の値に近づけば真っ当なサイコロではないと判断できるでしょう。

このような仕組みで、未知のパラメータを推定する手法をベイズ推定と呼びます。

おわりに

ベイズ統計学の世界の一端を垣間見ていただけたなら幸いです。冒頭でお伝えした機械学習に対する利用だけなく、ベイズ統計を利用することで回帰分析や仮説検定、時系列モデル分析など、様々な分析を行うことも可能です。またの機会にそれらについて、ご紹介できればと思います。

関連:ビジネスはAIの夢を見るか~AIがビジネスにもたらす価値~

受託開発における企画書の使い方

0

こんにちは。ゲームデザイン部のディレクターの江中です。
昨年に中途入社しましたが、それまでは自社開発の経験ばかりで、アピリッツで初めてゲームの受託開発を経験しました。

この記事では、ゲームディレクターの私が受託開発を進めていくにあたって、企画書を活用して後工程における問題発生防止のために工夫した点を紹介させていただきます。

ゲームの受託開発の流れ

企画書の話をする前に、前提としてゲームの受託開発の流れをご説明いたします。ゲームとはいってもソフトウェアであるため、基本は通常のソフトウェア開発の流れとなります。ソフトウェア開発には様々な手法があると思いますが、規模が大きいゲームの受託開発においては契約を分かりやすくするために、期間(いつまでに)と成果物(何をつくるのか)を明確に定めやすいインクリメンタル開発をすることが多いように思います。インクリメンタル開発とは、プリプロダクション版フェーズやα版フェーズといった形で期間と実装内容を定めて、そのフェーズごとに徐々に機能を追加していく形で実装していく方式です。大雑把なイメージとしては、次のような図となります。

インクリメンタル開発では機能ごとに開発していくため、全てが完成したときのUXを確認できるのが最後になり、大きなリスクがあります。また仕様変更があった場合に、細部まで作り込んでいるとその分多くの工数が無駄になってしまうことがあります。

インクリメンタル開発をより深く理解するために、よく比較されるイテレーティブ開発をご紹介いたします。上記のインクリメンタル開発の弱点を克服しようとしたのがイテレーティブ開発です。イテレーティブ開発では最初は最低限の機能しか実装しませんが、徐々に機能を増強したり操作性を高めたりして洗練させていきます。個人的にはゲーム開発においては、全体のUXを把握しながら開発できるこちらの方法がより向いているように思います。大雑把なイメージを示しますと次のような図になります。

インクリメンタル開発の各工程

インクリメンタル開発ではどのように機能開発していくのかを確認してきましたが、続いて工程がどのように進むのかを見ていきましょう。ちょうど五月雨式にウォーターフォール開発を繰り返すイメージで、次の図のような方式となります。

上記の図では、テストは1つの工程として表されています。しかし、実務においては企画から実装までの幅広い工程の結果をテストしていく必要があるため、実際にはテスト工程はいくつかの工程に分かれます。上流の各開発工程に対応させてテスト工程を分割したものをV字モデルといいます。V字モデルを図にすると、次のようになります。

V字の左側が開発工程で、右側がテスト工程となります。各工程では、次のようなことを実施します。

  • 企画工程(要求定義)では、「なぜそれをやるのか」という目的(ゴール)を定義し、その要素(機能や施策)によって何を達成したいのかを決めます。
  • 設計工程では、企画で決めた要素をどのように作成するのかを決めます。
  • 実装工程では、決めた通りにつくります。
  • 試験工程では、設計で決めた通りの仕様になっているのかを確認します。
  • 検証工程では、企画で決めた目的を達成しているのかを確認します。

今回は特に、この企画工程の成果物である企画書の使い方について取り上げています。

企画工程で目的・ゴールを整理・共有していないと失敗しやすくなる

入社前に私が経験した自社開発プロジェクトにおいては、各機能や施策の目的はディレクターやプランナーの頭の中にあるので、詳細な企画資料がない状態で設計工程から進行していくということがありました。しかし、設計工程で共有されるのが具体的な機能仕様や施策内容だけだった際には、UXを作り込むデザイナーやエンジニアに目的が伝わらずに、ディレクターや担当プランナーが意図したものにならないこともありました。またプランナー間連携においても、例えば企画工程担当と設計工程担当のプランナーが異なるケースでは、企画工程で定めた目的に合わない内容の仕様書が、設計工程で作成されてしまうことがありました。

例えばキャラクターに「超必殺技」という要素を追加するといった場合に、ARPPU向上を目的にキャラを重ねてもらう施策として導入するのか、継続率向上を目的にキャラクターにパラメーター的な個性を付与してデッキ編成に創意工夫の幅を持たせる施策として導入するのかでは作るべき仕様が大きく異なります。しかし、企画工程で目的を定めていなかったり、設計工程担当プランナーがディレクターへの確認を怠ったりすると、キーワードだけで仕様作成が進んでしまって、目的と合わない仕様が作成されてしまうことがあったのです。

顧客と目的・ゴールを握り、後工程で確認できるように資料化する

自社開発にもある程度当てはまると思いますが、特に受託開発で何か要素を新規開発する際には、目的・ゴールを企画工程で企画書にまとめ、顧客と話し合い共通認識を持ってから設計工程以降を進めると社内外での調整がスムーズに行くように思います。企画書にどのKPI向上を目指すのか、あるいはどのような体験をつくろうとしているのかといったことを書いておき、いつでも参照できるようにしておくのです。

社内においては、まず設計工程担当プランナーは企画書を踏まえて仕様書を作成することができるようになります。また仕様書の完成後に、企画工程担当プランナーを含むレビュアーが、その仕様が実装されることで目的・ゴールが達成されるのかという視点で確認できるようになります。このときUXに詳しいデザイナーや、内部設計に通じたエンジニアが含まれていると、目的をより良く実現できる設計を提案してくれるかもしれません。そして仕様書レビューに参加できなかった実装担当のデザイナーやエンジニアも、企画書を読むことで目的を知ることができるため、実装上の内部的な作り込みも、より良くできるかもしれません。

社外、すなわち顧客においては、握った目的・ゴールの内容を、その後の設計工程の成果物であるソフトウェア仕様書や、検証工程で「企画で決めた目的を達成しているのか」を確認していただく際に基準として活用することができます。誰でも数ヵ月前の記憶は曖昧になりがちなので、どういった目的のために何をつくるのかということを定めた企画書を作成して残しておくと、認識違いが起こりにくくなります。

私が参加したプロジェクトでは、該当フェーズで新規実装した要素が多かったので、ゴール設定資料といった形で①新規実装要素、②その目的、③目的を達成したか否か、の3点を一覧にまとめてご確認いただくことで、比較的スムーズに検収していただくことができたと思います。具体的には次のようなイメージの表を用意し、顧客と該当フェーズで新規開発した要素について認識合わせをさせていただいた形です。

最後に

トヨタ式の鉄則として「前工程は神様、後工程はお客様」というものがあります。特にゲーム受託開発では契約の分かりやすさから、インクリメンタルなウォーターフォール開発に近い方式を採用することが多そうなゆえに、この鉄則が当てはまりやすいように思います。よってディレクターや企画工程を担当するプランナーは、後工程に大きく影響することを理解し、企画(要求定義、要件定義)の品質を高めていくことが求められるように思っています。

またゲーム開発においては実際にプレイしてみないとUXが分からない部分も少なくなく、顧客からインクリメンタル開発的な契約でありながらイテレーティブ開発のようなご要望をいただくこともあります。そういった個所を先回りして検知し、AdobeXDによるモックで念入りに確認したり、あらかじめブラッシュアップ期間に修正していくと方針を決めておいたりする先見性も必要になると思います。

私自身、過去の成功体験が異なるチームメンバーや顧客とどのように認識を合わせながら進めていくべきかを模索しながら進めた方法論となりますが、この記事が読んでいただいた方の一助になれば幸いです。

今年はオンライン開催! 2021年 新卒内定者 顔合わせ会

0

イベント開催やパーティーが難しかった2020年もそろそろ終わります。本来ならば実施していたはずの「内定式」も取りやめ……でも、アピリッツには今年もたくさんの内定者がいます。2021年4月の入社にむけて、内定者同士、そして会社と内定者のみなさんが、お互いを知る機会を設けたい。ということで人事企画部が「内定者顔合わせ会」をオンライン上で開催しました。(2020年12月 取材)

オンラインイベントを盛り上げるために

すでに内定者アルバイトとして仕事に参加しているメンバーもいますが、多くの内定者はオンライン上で初めてお互いの顔を見ます。緊張もするでしょうし、はたして盛り上がるのか? 盛り上げられるのか!? ……ということで、人事企画部の採用担当者からの渾身の前説。「拍手をしよう!」「リアクションはどんどん出していきましょう!」と呼びかけ、場をあっためました。

たぶん通常よりもテンション高め。

そして自己紹介。オンラインからの参加者もいれば、

笑顔がすてき

内定者アルバイトとして会社に来ている内定者からの挨拶も。

人事企画部も広報の私たちも、内定者の皆さんの意外な一面を知ることができました

自己紹介のあとはクイズをやってみたり……、

みんなでワイワイしながら会社とお互いのことを知っていきます。

会社にまつわるちょっとしたクイズを実施。アピリッツの代表取締役社長執行役員CEOの名前は和田順児です

Zoom越しでも明るく丁寧にコミュニケーションをかさねると、なんだか楽しくなってくるものなんですね。で、場があったまったかな……というタイミングで、数人の班にわかれてアピリッツの事業やサービス、会社の特徴について考えるグループワークをおこないました。

内定者アルバイトとして出社しているメンバーはアピリッツの会議室から顔合わせに参加

グループワークとそれぞれのチームの発表のあとは、オフィスの様子を見てもらうための社内見学ツアーも実施しました。これ、オフラインでも入社前に「こんな感じで働いてますよ」と見てもらうことがあります。それのオンライン版です。

ファンサを求める人の気持でのぞんだはず

事前に全社員に「オンラインで社内見学をおこなうのでよろしくね!」お知らせしていたので、オフィスにいる社員が手をふってくれました。ご協力ありがとうございました! 内定者のみなさん、4月にあえることを楽しみにしています!

Google スプレッドシートの便利関数-part1-

0

コンテンツデザイン部の江川です。

データを扱う際に皆さんは何を使っていますでしょうか。様々あるとは思いますが、多くがexcelかGoogle スプレッドシート(以下スプレ)のどちらかを使用していると思います。
excelとスプレどちらを使うにも利点がありますが、多くの方がスプレってクラウド版のexcelでしょ。くらいの認識なのではないでしょうか。
私も最初はそうだったのですが、実は結構excelとスプレって違うんです。
そこで今回はクラウド化の波に乗ってexcelからスプレに変えた方やちょっとしたデータをみんなで触れる方が便利だからとスプレを使用している方に、今日から使えるスプレならではの便利関数を紹介します。

1.ARRAYFORMULA

スプレといえばこれ!といった関数です。スプレを愛用している方々の中にはこの関数が使えるからスプレにしているという方も少なくないでしょう。
ARRAYFORMULAとは一つのセルの式を配列形式で表示する関数です。

という方にもわかりやすいように、言い換えると一つのセルの数式をそれ以下の行or列に適応する関数です
以下のように点数から成績の値を算出する数式をIFS文で90点以上ならA、50~89はB、31~49がC、それ以下は赤点と定義します。
C3に数式を入れるともちろんC3セルに結果が算出され、この式を下に伸ばすと数式も下に伸びていきます。

しかし、ARRAYFORMULA関数を同じセルに適用すると……

このように、IFSのみの場合だとB3と一つのセルしか指定できませんでしたがARRAYFORMULAを加えることによってB3:Bの範囲全ての結果がC3:Cに反映されるようになります。

イメージでは数式の中でセルを指定していた部分を範囲指定に変えることでARRAYFORMULA式が機能するようになります。もちろんB3:B50のように特定の範囲も指定できます。

これの何が便利かというと利点は2つあります。
・セルを下に伸ばさなくても自動で入力されること。
  →大したことないと思うかもしれませんが使ってみるとこれがすごく便利です。Excelで行っていた作業を単純に1段階減らすことになり、なおかつ漏れやミスが減ることが大きいです。

・計算処理が圧倒的に軽いこと。
  →外部の方とデータを共有する時などに大きなデータでも、この関数を使って軽量化することでお互いストレスフリーで作業することができます。逆にスプレを共有して大量のセルに参照数式が入っているととても重くなり、お互いの作業効率が落ちてしまうことになるので気をつけましょう。

こちらがARRAYFORMULAを使った数式です。

ARRAYFORMULA(配列数式または、非配列関数で配列を使用)
例:ARRAYFORMULA(IFS(~~~)

2.IMPORTRANGE

こちらはスプレッドシートを使いこなす上で非常に重要な関数となっています。

これは先ほどのARRAYFORMULAフォルダとは違うIMPORTRANGEというタイトルのスプレのA1セルにIMPORTRANGE関数を適用したものです。

別のスプレッドシートから値を参照できるわけですね。

この関数は
=IMPORTRANGE(“スプレッドシートキー”,”そのスプレの範囲指定”)
となります。
スプレッドシートキーというのはそのスプレのURLのことです。関数にはhttps://~から入っていますが、キー部分は1H7Uj~の部分なので本来であれば不必要ですがどちらでも問題はありません。

なので今回で一番スマートなのは
=IMPORTRANGE(“1H7Uj2vFP64dCYtaKI_cEm7zlc0mYEowD5J2d9tRBfj0″,”シート1!A:C”)
ですね。

Excelでも別のフォルダからの参照はできるのですが、スプレの大きな違いはクラウド管理だということ。
IMPORTRANGEで出されたデータは元のスプレの値をリアルタイムで持ってこれるのでやはり複数人で同じデータを触る際に便利です。

いちいちURLをコピペするのが手間な人向け小技

画像のようなリストを作って、B列のキーを使う予定のフォルダにIMPORTRANGEします。
そのフォルダで別シートを参照する際はセル指定でIMPORTRANGEが使えます。
=IMPORTRANGE(‘画像シートの名前’!B2,”参照元シート名!範囲”)

つまり=IMPORTRANGE( まで入力してセルをクリックするだけでURLを入力しなくてもよくなる!という寸法ですね。

正直、上記の2つの関数をマスターするだけでスプレッドシートを使用していく上で十分に快適なデータ管理を行えるでしょう。
なので残り3つはgoogleならではの簡単で便利な関数を紹介します。

3.IMPORTHTML

例えばサイトで画像のような表のデータをスプレに入れたい時どうしますか?

いちいち手入力するのは手間ですよね。しかも頻繁に内容が変わるようなサイトの内容だったら毎回確認して変わってたら書き換えないといけない。

そんなお悩みを解決するのがIMPORTHTMLです。
こちらの関数はHTML内の表やリストをそのままスプレに持ってくることができます。

頻繁に使う機能ではないですが、資料やデータを作る際の時間短縮になると思います

=IMPORTHTML(“URL”,”table or list”,指数)
画像の場合だとURLのHTML内で2つ目のtableを展開しています。

ゲーム会社だと公式HPに載せるスケジュールテーブルとゲーム内の時間がズレないようにこういった関数を使って整合性を取る!なんて形もありかと思います!

4.IMAGE

スプレを他人に共有する際。資料として渡すのであれば画像があると伝わりやすいですよね。
イメージとしてネットで拾った画像を共有することは少なからずあると思います。
そんなとき、一々検索して画像を保存して貼り付けて…って自然にやると思いますが意外とめんどくさかったりします。

そこでこのIMAGE関数。

アピリッツのバナー

URLがあれば画像をスプレに表示させることができます。

=IMAGE(“URL”,モード,高さ,幅)

モードは以下のようにセル依存、アスペクト比依存、サイズ依存、自由のようにサイズを指定できます。

1アスペクト比を変えずに、セル内に収まるように画像サイズを変更します。
2アスペクト比を無視して、セル内に収まるように画像を引き延ばすか決めます。
3画像を元のサイズのままにします。その場合、画像がトリミングされることがあります。
4カスタムサイズに変更することができます。

デザイナーさんなどは自社のサイトに画像を載せた際、そこにリンクしたこの関数を使うといちいち更新しなくて良いので便利かもしれません。

5.GOOGLETRANSLATE

英語のデータやいろんな英文を一気に翻訳したいときにこの関数は役立ちます。
この関数はセルのテキストをGoogle翻訳する関数なのです。

Google翻訳の利点といえばなんと言ってもコスト以上の精度と翻訳言語数にあります。
無料でここまでパッと翻訳できるサービスは他にないでしょう。
もちろん文章が長ければ精度は落ちますが、それでも昔に比べて相当な精度で翻訳を行ってくれます。

画像は単語帳をリスト化した物ですが、こう言った自分なりの単語帳を作る時などにも使えるかもしれませんね。

翻訳する数が膨大な場合はこの関数を使って一覧にすると纏まったデータになるかと思います。

最後に:次回へ続く

いかがでしたでしょうか?スプレを使う上で必須のARRAYFORMULAとIMPORTRANGE、その他3つは作業の効率化に役立つような小技的関数でした。

次回はデータ整理に便利な関数4選を紹介しようと思います。

最近人気な記事