Quantcast
Channel: Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)
Viewing all 223 articles
Browse latest View live

CodeBuildでサーバレスバッチ環境を運用する

$
0
0

この記事は Akatsuki Advent Calendar 2018の15日目の記事です。 前回は sejimhpさんの、環境改善の必要性〜真っ白な Terminal から tmux へ移行〜でした。

はじめに

システムを運用する上で、安価で運用負荷の少ないバッチ処理を設計したいニーズは多いと思います。そもそもバッチ処理自体を極力除外したいのですが、日々の運用ツールなども含めると、どうしても実装しなければならない場面が出てきます。

本記事では

  • 安く
  • サーバレスで
  • 並列性高く
  • スケジューラでもイベントドリブンでも

実行できる、AWS上でのバッチ環境の実装の話をしたいと思います。

よくあるAWSバッチ処理アーキテクチャパターン

AWSバッチ処理アーキテクチャパターンBest Practice for Online Game Development on AWS が詳しいです。これらのアーキテクチャに対して私見をまとめると

EC2パターン

  • Pros: シンプルで使いやすく、速やかに実装ができる。
  • Cons: EC2料金が常にかかる。環境変数などの運用管理も必要。

Lambdaパターン

  • Pros: サーバレス。AWSのリソースを扱うには便利。
  • Cons: ゲームアプリケーションのロジックなどは使い回せない。タイムアウトも短め。

ECSパターン

  • Pros: CodePipeline等のパイプラインに組み込める。
  • Cons: 結局EC2が必要で、かつバッチで使うには比較的複雑。

Fargateパターン

  • Pros: サーバレス。
  • Cons: コストが割高で、プロビジョニングに1〜2分かかる。

例を挙げればAWS Batchなどのサービスもあるのでキリがないのですが、結局似たようなProsConsになるかと思います。今回は、これらのアーキテクチャを使わず、CodeBuildでバッチ処理を実装をする話をしていきます。

CodeBuildとは?

AWSが提供するマネージドビルド環境で、buildspec.ymlに記載した通りにビルドをすることができます。  

よくあるCodeBuildの使い方

通常、docker build用の環境などに用います。 弊社でもdocker buildが主な用途で、CodeBuildでdocker build後、ECRへdocker pushし、ECS / Fargateへデプロイするために使用しています。

f:id:e__koma:20181214155303p:plain
CodeBuildの使用例

buildspec.ymlの例は以下のとおりです。 パラメータストアと連携して秘匿情報をセキュアに一元管理したり、ビルド済みのdocker imageを実行環境として使えるところも嬉しいです。

version:0.2env:parameter-store:AWS_ACCESS_KEY_ID:"project-id.aws.access.key.id"AWS_SECRET_ACCESS_KEY:"project-id.aws.secret.access.key"phases:pre_build:commands:- echo Logging in to Amazon ECR...
      - aws --version
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
      - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}
  build:commands:- echo Build started on $(date)
      - echo Building the Docker image...
      - |
        docker build -t ${REPOSITORY_URI}:latest -f ${DOCKERFILE_PATH} . \
        --build-arg YOUR_ENV=${YOUR_ENV}
  post_build:commands:- echo Build completed on $(date)
      - echo Pushing the Docker images...
      - docker push ${REPOSITORY_URI}:latest

CodeBuildを使用したバッチ環境

さて、本題です。 CodeBuildを使ってバッチ処理を実行する方法を説明します。

パターン1:バッチスクリプト実行

CodeBuildはビルド環境に様々な言語が用意されており、かつVPC内で実行することができるため、RubyPythonスクリプトを実行することができます。

f:id:e__koma:20181214170023p:plain
CodeBuildでスクリプト実行例
 

実行後はCloudWatchEventsでイベントフックをして、slack通知をしてもいいですし、Lambdaで別の処理に移行するのも良いでしょう。CodePiplineやJenkinsのAWS CodeBuild Pluginを使用したPipelineに組み込めば、前後関係を豊富にカスタマイズできます。

この場合のbuild_spec.ymlは非常にシンプルに書けます。

version:0.2env:parameter-store:YOUR_ENV:"your.env"phases:build:commands:- python ./test.py
artifacts:files: test.log

 

パターン2:ビルド済みアプリケーションの実行

  パターン1ではスクリプトを実行するだけでしたが、ビルド済みのアプリケーションを使った運用ツールを実行したい場合があります。例えばデータベースのmigration、 ゲームアプリケーションロジックを用いたアイテムドロップシミュレータなどです。

この要望を満たすためには、ビルド済みのアプリケーションImageを再度CodeBuildにpullしてこればOKです。

f:id:e__koma:20181214171045p:plain
CodeBuildでビルド済みアプリケーションの実行例

この場合、build_spec.ymlには少し工夫が必要になります。 ビルド済みのImageをpullしてきた後、docker runをする際にENTRY_POINTを空にして、実行したいコマンドを渡します。 こうすることでENTRY_POINTを無視して、ビルド済みのアプリケーションに対してコマンドを実行することができます。

version:0.2env:parameter-store:YOUR_ENV:"your.env"phases:pre_build:commands:- echo Logging in to Amazon ECR...
      - aws --version
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
      - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}
  build:commands:- echo started on $(date)
      - docker pull ${REPOSITORY_URI}:latest
      - echo ${BATCH_NAME} starting ...
      - |
        docker run \
        -e YOUR_ENV=${YOUR_ENV} \
        --entrypoint="" -i ${REPOSITORY_URI}:latest \
        sh -c "${BATCH_COMMAND}"post_build:commands:- echo ${BATCH_NAME} completed on $(date)

さて、ここまで説明してきたCodeBuildでのバッチ処理のメリットをまとめます。

機能性

  • ビルド済みのアプリケーションロジックを使い回せる
  • VPC内で実行できるためEC2 / RDSなどへのアクセスができる
  • 並列性が高い。
  • リソースの範囲内であれば長時間バッチも可能

運用性

  • サーバレス
  • 成功・失敗のイベントフックが豊富
  • Pipelineへの組み込みが容易なため前後関係の定義ができる

コスト

  • 従量課金のため、とにかく安い。

デメリットを挙げるとすれば以下のとおりです。

デメリット

  • プロビジョニングに30秒ほどかかる(ただしFargateのプロビジョニングよりかは速い)
  • 使える最大リソースは8vCPU、15GBメモリなので、これ以上のパワーが必要な処理ではリソースが足りない。

まとめ

CodeBuildを使ったバッチ処理を紹介してきました。 CodeBuildをバッチ環境として使い始めたプロジェクトでは、バッチサーバという概念がなくなりました。 興味がある人は、ぜひ使ってみてください!


React Native製アプリのフォントサイズをいい感じに設定したい

$
0
0

そとあそび所属の天野(@mutachii) です。

この記事は Akatsuki Advent Calendar 2018の17日目の記事です。
前回は s-capybaraさんの、Elixir でソースコードジェネレーションする - Qiitaでした。

はじめに

React Nativeでの開発で避けて通れないのは、多種多様なスクリーンで表示崩れを発生させないように実装することです。

幸い、Flexboxのサポートのおかげでレイアウトの実装で困ることは少ないですが、対応が面倒なのが fontSize の指定だと思います。
これらは当然 Flexbox では対応することができないし、widthやheight, paddingなどのようにパーセント指定することもできません。

React Native 開発始めたてのときにあるある(だと思っている)のは、普段は iPhoneX で動作確認している開発者が、
いざリリースするぞとなったタイミングで、iPhone8やiPhoneSEでは文字が大ぎることや、 逆に、iPadで確認すると文字が異様に小さいということに気づき対応に追われるということじゃないでしょうか...

今回は、そのfontSize 問題の解決に有用な

という2つのライブラリを紹介します。

react-native-size-matters

以下のように使うライブラリです。

import{ scale, verticalScale, moderateScale } from 'react-native-size-matters';

const Component = props =>
  <View style={{
    width: scale(30), 
    height: verticalScale(50),
    padding: moderateScale(5)
  }}>
    <Text style={{
      fontSize: moderateScale(14)
    }}>すごい</Text>
  </View>

このscaleやverticalScaleがやっていることはすごく単純で、 基準となるスクリーンサイズ(350 x 650)に対する、現在のスクリーンサイズの倍率を算出して、その倍率をかけた数値を返してくれます。 それだけなので、fontSizeはもちろん、widthやheightにも利用できます。

moderateScaleだけはすこし特殊で、

Sometimes you don't want to scale everything in a linear manner, that's where moderate scale comes in.
The cool thing about it is that you can control the resize factor (default is 0.5).
If normal scale will increase your size by +2X, moderateScale will only increase it by +X, for example:
➡️ scale(10) = 20
➡️ moderateScale(10) = 15
➡️ moderateScale(10, 0.1) = 11

というように、増加 / 減少 させるときの係数を指定できます。 スクリーンサイズが2倍になったからといって、すべての要素のサイズを2倍にしたいわけではない...というようなケースで使います。

微妙に問題になるのは、基準となるスクリーンのサイズが 350 x 680 という値なので、例えば デザインデータが iPhoneXで作成されている場合は、デザインどおりに実装できないことです。
とはいえ、上に書いたとおりとてもシンプルな実装なので、自分たちの基準となるスクリーンサイズを使って実装し直すという方法もありそうです。

react-native-responsive-fontsize

名前通りに responsive な fontSize の指定を可能にする RFという関数を提供してくれます。

import RF from "react-native-responsive-fontsize"const styles = StyleSheet.create({
  welcome: {
    fontSize: RF(3.5),
    textAlign: "center",
    margin: 10
  },
  instructions: {
    textAlign: "center",
    color: "#333333",
    marginBottom: 5,
    fontSize: RF(2.5)
  }})

こちらの実装もシンプルでデバイスのHeightを基準にフォントサイズを決めます。なので、RFの引数は fontSize ではなくて パーセンテージ であることに注意してください。

さいごに

fontSize問題にすぐ効く2つのライブラリを紹介しました。

基本的には薄い実装のライブラリ達なので、実装の方向性を確認して、自分たちのプロダクトに合わせて改変していくことや、
PRを出してライブラリ自体を改善しやすいのかなと思っています。

UnityでAPK拡張ファイルを利用するときのあれこれ

$
0
0

こんにちは。このブログでははじめまして。クライアントエンジニアの下村です。

この記事は Akatsuki Advent Calendar 2018の19日目の記事です。 
前回は kidach1 さんの ニューラルネットワークでStyle Transferを行う論文の紹介でした。

背景

この記事を開いた方にはご存知の事かと思いますが、Google Play Storeではアプリケーションパッケージのサイズに制限があり、100MBを超えるapkファイルをアップロードすることができません。 100MBを超える大きなアプリを提供したい場合は、APK拡張ファイルと呼ばれる別のパッケージにデータを分割する必要があります。

インターネット接続を前提とするソーシャルゲームでこの制限に引っかかることはそう多くありませんが、それでも急な対応でアプリサイズが大きくなってしまうことがたまにあります。

ちょうど最近、そういった不幸な出来事からこれを利用する機会があったので、備忘録を兼ねて知見を共有したいと思います。

UnityでAPK拡張ファイルを出力する

UnityでAPK拡張ファイルを出力する方法は非常に簡単です。 PlayerSettingsの Split Application Binaryオプションにチェックを入れてビルドすると、apkファイルと一緒にobbファイルが生成されます。 Unityは分割されたファイルから自動的にアセットを読み分けるため、Unityの実装上で分割を意識する必要はほとんどありません。

分割したアプリを手動でインストールする

Build And Runを実行するとUnityは自動的にobbファイルをインストールしてくれます。 一方手動でアプリをインストールする場合は、 apkファイルに加えてobbファイルを特定の場所に配置する必要があります。

obbファイルの名前や置き場所は決まっていて、以下のようなパスに配置する必要があります。
外部ストレージのAndroidディレクトリは端末によってパスが異なる事がある点に注意してください。

/storage/emulated/0/Android/obb/<パッケージ名>/main.<ビルド番号>.<パッケージ名>.obb

ファイルの転送には adb pushコマンドを使うのが便利です。

$ adb install App.apk
$ adb push App.main.obb /storage/emulated/0/Android/obb/jp.aktsk.testapp/main.1.jp.aktsk.testapp.obb

これで分割されたアプリをインストールすることができました。

APK拡張ファイルのバリデーション

obbファイルは通常apkファイルと一緒にインストールされますが、実態は外部ストレージに配置されるいちファイルに過ぎません。 アプリ起動時にファイルが存在しないという状況が起こりえることから、Googleはアプリ起動時にAPK拡張ファイルのチェックや再ダウンロードを行うよう喚起しています。

Googleからはobbファイルをバックグラウンドでダウンロードするライブラリが公開されていますが、今回は急ぎで対応が必要だったことからこの高機能なダウンローダーを実装して詳しく検証している時間がありませんでした。 幸い分割されたデータはそう大きくなく、最近ではダウンロード漏れもかなり稀な発生率であるらしいことから、起動時に簡単なファイルチェックのみを行うことにしました。

APK拡張ファイルをチェックするアクティビティを挟む

今回のアプリではUnityの起動直後にいくつものアセットを読み込んでいたため、UnityPlayerActivityが起動する前にobbファイルの存在チェックをする必要がありました。 そこでonStartでobbファイルの存在をチェックをするActivityを新しく作成します。

publicclass ExpansionFileCheckActivity extends Activity {
    @Overrideprotectedvoid onStart() {
        super.onStart();

        if (getMainObbFile().canRead()) {
            // UnityPlayerActivityを起動するreturn;
        }

        // エラーを表示してアプリを終了する
    }

    private File getMainObbFile() {
        String fileName = "main." + getVersionCode() + "." + getPackageName() + ".obb";
        returnnew File(getObbDir(), fileName);
    }

    privatelong getVersionCode() {
        try {
            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            return PackageInfoCompat.getLongVersionCode(packageInfo);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return0;
        }
    }

    // (省略)
}

getObbDir()でobbファイルの配置されるディレクトリを取得できますが、ファイル名は自分で生成する必要があります。 Activityを追加したら、AndroidManifestを修正して最初に起動するActivityを置き換えます。

<activity android:name="jp.aktsk.testapp.ExpansionFileCheckActivity"android:label="@string/app_name"android:launchMode="singleTask"android:theme="@style/Theme.AppCompat"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name="com.unity3d.player.UnityPlayerActivity"android:label="@string/app_name"android:launchMode="singleTask"><meta-data android:name="unityplayer.UnityActivity"android:value="true" /></activity>

これで起動時に問題があれば適切なエラーを表示することができるようになりました。

必要なときだけアクセス権限を要求する

さらに一部の端末ではインストールされたobbファイルがユーザ所有にならず、アプリからアクセスできなくなることがあるようです。 Unityはこの問題を回避するため、 Split Application Binaryオプションを有効にしてビルドすると READ_EXTERNAL_STORAGE権限要求をAndroidManifestに自動で付与します。

しかしながら、ごく一部の端末のためにすべてのユーザーにこの強力な権限を要求するのはナンセンスです。ここはobbファイルが読み込めなかった場合にのみ権限を要求するようActivityを拡張しましょう。

publicclass ExpansionFileCheckActivity extends Activity {
    privatestaticfinalint RC_PERMISSION_REQUEST = 1;

    @Overrideprotectedvoid onStart() {
        super.onStart();

        checkApkExtension();
    }

    @Overridepublicvoid onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNullint[] grantResults) {
        if (requestCode != RC_PERMISSION_REQUEST) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            return;
        }

        if (grantResults.length == 0&& !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
            // アプリの設定画面を開くreturn;
        }

        checkApkExtension();
    }

    privatevoid checkApkExtension()
    {
        if (getMainObbFile().canRead()) {
            // UnityPlayerActivityを起動するreturn;
        }

        if (PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.READ_EXTERNAL_STORAGE
            }, RC_PERMISSION_REQUEST);
            return;
        }

        // エラーを表示してアプリを終了する
    }

    // (省略)
}

ファイルチェックに失敗した場合は READ_EXTERNAL_STORAGE権限をチェックし、なければリクエストしてから再度チェックを行います。 このときユーザーが「今後表示しない」をチェックしていると shouldShowRequestPermissionRationalefalseを返すので、一言添えてアプリ設定画面に誘導するとよいでしょう。

最後にUnity側の権限リクエストを無効化する設定をAndroidManifestに追加すれば完了です。

<meta-data android:name="unityplayer.SkipPermissionsDialog"android:value="true" />

これでなんとかAPK拡張ファイルを利用したアプリをリリースする最低限の準備ができました。 あとはお好みでユーザーへの説明や操作指示などを肉付けしましょう。

その他の注意点

バイナリの配布方法

利用しているアプリケーション配信サービスによってはobbファイルを取り扱えないことがあります。ストアの内部テストだけでは大抵不足なので、ビルドの用途に応じてAPK拡張ファイルの利用するか切り替えられるような仕組みを準備しておくべきでしょう。

StreamingAssetsへのアクセス

UnityでAPK拡張ファイルを利用するとStreamingAssetsはobbファイルの側に格納されます。AndroidにおいてStreamingAssets以下のファイルへのアクセスはどちらにあってもそう変わりません。
しかし、一部のサードパーティライブラリではobbファイル内のStreamingAssetsに正常にアクセスできないものがありました。

StreamingAssets以下にあるアセットが正しく読み込まれているか検証を忘れないようにしましょう。

ビルド番号

Google Play StoreではAPK拡張ファイルのビルド番号はアプリ本体のものと別に扱われるようですが、Unityは必ずアプリのビルド番号を用いてobbファイルを開こうとするようです。 Google Play Storeで新しいリリースを生成するとき、新しいobbファイルをアップロードせずに過去のファイルを選択すると、Unityからアクセスできなくなってしまいます。 

まとめ

UnityでAPK拡張ファイルを扱うのは簡単ですが、その仕組みには落とし穴がいくつもありました。 アプリサイズが逼迫したときはまずより簡単な手順(例えば、アーキテクチャ毎にapkをビルドするなど)を講じて、なお足りない場合に採用を検討すべきでしょう。

その上でどうしても必要になったときは、Unityによるサポートがあるからと軽視せず早めに実装と検証を行うことが大事ですね。

エンジニア組織の責任範囲の透明性をRACI図で高めてみた

$
0
0

こんにちは、ゆのん(id:yunon_phys)です。この記事は Akatsuki Advent Calendar 2018の22日目の記事です。 前日は@kackytwさんのDQNの学習速度を改善するでした。

Engineering Managerのjob descriptionを共有する流れ

近年、Engineering Manager(EM)業界が賑わってきています。特に2018年は非常に活発化した年でした。書籍としては、エンジニアリング組織論への招待エンジニアのためのマネジメントキャリアパスという名著が生まれました。また、Engineering Manager Meetupが3回開催され、Slack workspaceでは12/22時点で268人となっています。EMのためのPodcastEM.FMも誕生し、総再生回数が10,000回を突破するなど、多くの方から注目を集めています。*1

私自身もEM Meetupには全て参加していて、毎回アツい議論が展開されています。 その中でも最近のHot TopicはEMのjob descriptionです。 この話の大元は、EM.FMの及川さんがゲストで参加されたep.8にあります。

及川さん: CTOとVPoEはいろんな形で説明したけれども、各社によって組織構造によっても違うし、役割も違う。これが一つと考えずに、ずっと話しているみたいに役割・job descriptionみたいなのを決め、あとはどういうふうな組織構造にするかをしっかり決めていくほうがよいのではないか

広木さん:2つありますよね。社内の中で明確に役割が決まっている、これが1つ良いことですよね。次のステージとして、社会として決まっていた方がいいというのもあって。転職するとか採用するときに、全体のキャリアパスとしてマネージメントキャリアを積んでいくことが、閉じたキャリアじゃなくなっていく。別の会社にもあるキャリアなんだな、スキルなんだな、というのが見えてくる。2ステップだなと思っています。 あまり各社でjob descriptionをはっきりしないで、公開もしないことが当たり前になってしまうと、社会に共有されるという次のステップにいかないだろうな、と思っていて。及川さんと話していて思うのが、社会でjob descriptionとか求めるものが共有されていって、人が循環していったり、人が高められているステージに早く日本をさせていきたいのかな、と思っていて。

及川さん: そうですね、人材の流動性とかを考えたときにそれはあって、各社ごとに違うといっても、これはこういうCTOです、ということがなんとなくわかって、自分自身ちゃんと説明できるのが良いのかな、と。

このやりとりを聞いて、エンジニア組織のマネージャーのjob descriptionを共有していく取り組みは良い方法だと感じました。 なぜなら、CTO/VPoE/EM/Tech Leadの役割分担が言語化されておらず、一方で他社のEMと話しても組織によってそれぞれの役割が大きく異なっていて、役割を一般化することに苦戦していたためです。

この流れを受けて、EM MeetupのコミュニティでEMのjob descriptionを作ろう、とSlack workspaceで呼びかけてみました。 幸いにも賛同してくださる方が多く、少しずつ進み始めています。 先日のEM Meetup #3でも、約10名のEMの方々と議論が出来ました。

コミュニティとしては、いきなりジェネラルなjob descriptionを作ろうとするのではなく、各社がそれぞれの組織の状態や責任範囲を持ち出し、 そこからCTO/VPoE/EM/Tech Leadの役割を定義していく流れになっています。 そのいちアウトプットとして、本エントリーでは、アカツキのエンジニア組織の状態をRACI図で読み解いてみます。

RACI図とは

RACIとはResponsible(実行責任者)、Accountable(説明責任者)、Consult(相談先)、Informed(報告先)の頭文字をとった言葉で、RACI図はプロジェクト管理で役割/分担を明確にするためのPMBOKにも定義されているフレームワークです。 ある役割やタスクに対して、R/A/C/Iを定義することで、円滑にものごとが進むことをRACI図で期待しています。

CとIは比較的わかりやすいですが、RとAはわかりづらいので、補足で説明します。

responsibilityとaccountabilityの違い

responsibilityとは、実行責任と訳されます。responsibilityを保持している人は、あらゆる手段を使って困難を解決する責務を持っています。 responsibilityを保持している人は1人とは限りません。

一方、accountabilityとは、説明責任と訳されます。*2 accountabilityを保持している人は、誰にいつ聞かれても説明出来る責任を持っています。 accountabilityを保持している人は1人に限定されます。

RACI図を作ってみた

アカツキでは、エンジニア組織の役割として、CTO、VP of Engineering(VPoE)、EM、Lead Engineer(LE)、Memberと分かれています。 アカツキにおけるエンジニア組織のおおまかな役割の違いは以下の通りです。

役割業務内容サマリー
CTO全社の技術な意思決定者
VPoEエンジニア組織のマネージメント
EMプロダクト/プロジェクトの開発マネージメント
LEプロダクト/プロジェクトの技術意思決定者
Memberプロダクト/プロジェクトの開発

f:id:yunon_phys:20181220164501p:plain
アカツキの組織概念図

さっそく、結果を見てみましょう。

責務CTOVPoEEMLEMember
Big pictureを描くA,RCCCC
社内情報システムのテクノロジーの採用A,RCCCI
エンジニア組織づくりIA,RRRR
エンジニアのアサイlA,RRCC
エンジニアの評価(LE)A,RI
エンジニアの評価(Member)IARRC
エンジニアの評価(EM)IA,R
エンジニアの評価制度設計A,RRCCC
エンジニアの採用A,RRRRR
エンジニア決裁(一定額以上)A,RRRRR
エンジニア決裁(一定額未満)A,RRRR
プロジェクト内のテクノロジーの採用CCCA,RR
プロジェクト内の開発チームの組成IA,RRR
プロジェクト内の開発チームのピープルマネージメントIA,RR

何やらたくさんありますが、少しずつ読んでいき、現状のアカツキのエンジニア組織を読み解いていきましょう。

CTOとVPoEの責任の違い

まず、CTOとVPoEがそれぞれaccountabilityを保持している理由を説明します。 アカツキのエンジニア組織のaccountabilityは基本的にCTOが保持します。 一方、CTOの方が技術サイドの志向性が強かったり、VPoEの方が組織サイドの志向性が強い、という特徴もあります。 そのため、CTOからVPoEに一部を権限移譲(委譲ではない)する形でエンジニア組織を成り立たせています。 結果として果たすべき業務に対して、accountabilityをCTOとVPoEが持っていることにつながっています。

さらに、VPoEがaccountabilityを保持しているとき、CTOはInformed(結果を通知される)あるいは空欄(責任なし)になっていることがわかります。 これは権限移譲をした業務に対して、CTOとして結果は知らせて欲しいのか、完全に任せたいのか、という意思を表しています。 CTOのこの2つの意思をはっきりさせるために、以前本ブログで事例紹介したManagement 3.0のDelegation Boardを使いました。

Delegation Boardは、以下のように権限委譲を7段階で表現します。

  1. 指示する :管理者として意思決定を行う。
  2. 売り込む :意思決定についての人々を納得させる
  3. 相談する :決定する前に、チームからの意見を得る
  4. 同意する :チームと一緒に決定を下す
  5. アドバイスする :チームによる意思決定に影響を及ぼす
  6. 問い合わせる :チームの決定後のフィードバックを求める
  7. 移譲する :特に影響を及ぼさずチームに任せる

権限を委譲する*3とは、責任を委譲することにもなりますが、RACIでも表現することが出来ます。 特に、accountabilityの移譲の分かれ目がDelegation Level 1~5と6~7です。

Delegation Level 1~5はマネージャーがaccountabilityを保ったままとなります。 逆にaccountabilityをメンバーに移譲すると考えると、マネージャーの役職もセットでやらなければ整合性が合わなくなります。

Delegation Level 6~7はresponsibilityとaccountabilityの移譲です。 6は結果をマネージャーが結果を尋ねる、なので、マネージャーがInformedとなります。 一方、7は完全にチームを任せて移譲する、なので、マネージャーは一切タッチしなくなります。

以上から、Delegation BoardとRACIは以下のように対応していると考えて、RACI図に反映しました。

Delegation LevelCTOVPoE
1(指示する)A,R
2(売り込む)A,RI
3(相談する)A,RC
4(同意する)A,RR
5(アドバイスする)AR
6(問い合わせる)IA,R
7(移譲する)A,R

VPoEとEMの責任の違い

RACI図でアカツキの特徴を表しているのは、エンジニアのアサインとエンジニア評価(Member)です。 ここではこの2つに着目します。

エンジニアのアサインの責任

アカツキでは、Matrix型組織を成しており、基本的な意思決定はプロダクト/プロジェクト(簡単のためプロジェクトとします)内で完結するようになっています。

各プロジェクトに1人はEMがいることになっていて、EMがそのプロジェクトに必要となるエンジニアを採用したり、他のプロジェクトから勧誘したりします。このため、EMにはエンジニアのアサインのresponsibilityがあります。 一方、VPoEは組織全体を俯瞰して、ビジネス的な視点でどのエンジニアがどのプロジェクトにいるべきか、の最終的な責任(accountability)を負うようになっています。

エンジニアの評価の責任

アカツキのエンジニア組織は、常に近くにいる人が評価をするのが適切である、という考えを持っています。 このため、プロジェクトに所属するEMあるいはLEがresponsibilityを保持し、プロジェクトのMemberを評価するようになっています。 VPoEの立場としてはMemberがどのような評価をされたのかのaccountabilityを保持していますが、直接的にはMemberの評価をしません。*4

EMとLEの責任の違い

EMとLEの役割の一番の違いはプロジェクト内のテクノロジーの採用と、開発チームのマネージメントです。

テクノロジーの採用の責任

プロジェクト内のテクノロジーの採用の責任は、LEがaccountabilityを持つようになっています。 これはアカツキの基本的な考え方が、最適な技術は最前線に立っているメンバーが適切に判断出来る、となっているためです。 このため、より現場に近い立ち位置のLEが技術的な意思決定をしています。

開発チームのマネージメントの責任

開発チームのマネージメントの責任は、EMがaccountabilityを持つようになっています。 これは、プロジェクトの達成したい目標を実現可能となる開発チームをどのように組成すれば良いか、 チームが潜在的に持っている力を100%発揮させるためにどうすれば良いか、を観察して実行する役割をEMが担っているためです。 そのために目標設定であったり、1on1であったり、開発チームの足りない役割を一時的に埋めたりします。

その他特徴的な事項

エンジニアの採用は全エンジニアがresponsibilityを保持している

エンジニアの採用には、全員がresponsibilityを保持しています。 面談、面接、懇親会など、あらゆる場面で、アカツキの顔として出ていくことを期待しています。

エンジニア決裁は全エンジニアがresponsibilityを保持している

決裁者(accountable)としてCTOあるいはVPoEが保持していますが、決裁が必要となる行動のresponsibilityは全エンジニアが保持しています。 これはアカツキに所属しているエンジニアは自由に行動出来ることを保証していて、かつ、悪いことをしないという信頼をベースに構築された組織としているためです。

RACI図は組織の状態を映し出す

RACI図を作る過程で、CTOとVPoEのaccountabilityの明確化したり、Delegation Boardを更新して、組織の現状がより明確になりました。 これにより、エンジニア組織の責任範囲の透明性が高まった感覚があります。

面白かったのは、RACIが自分の思っていた以上に組織構造に強く依存していた、ということです。 これはつまり、組織構造を考慮せずにjob descriptionを作ることは出来ない、ということを示唆しています。

他でも組織構造とRACI図が作成され、公開されていくと、双方にとってメリットのある取り組みとなりそうですね!

*1:このPodcastはエンジニアリング組織論への招待の著者である広木さんと、私がやっています

*2:説明責任は誤訳である、という論調もあります

*3:委譲という言葉と、移譲という言葉がありますが、前者はDelegation of authorityで、後者はAuthority transferなので意味が全く異なります。

*4:VPoEもEMとしてプロジェクトに所属しているので、EMのresponsibilityとして評価はしますが

ElixirのサーバアプリケーションをDatadog APMでトレースする

$
0
0

この記事は Akatsuki Advent Calendar 2018の23日目の記事です。 前回は id:yunon_physさんの、エンジニア組織の責任範囲の透明性をRACI図で高めてみたでした。

はじめに

アカツキではElixirを使ってゲームのAPIサーバを開発・運用しています。 ゲームのAPIサーバは、大量のリクエストを低いレイテンシで捌くことが要求されるため、ErlangVMの高いスケーラビリティが利用できるのは効果的です。加えてRubyなどを書き慣れている人にとっつきやすいElixirの文法も魅力です。

とはいえ、その性能を引き出すためには、やはりアプリケーションのパフォーマンスチューニングは不可欠です。 その際、"Don't guess, measure"という言葉の通り、どこを改善すれば良いかを知るための良い計測ツールが必要になります。

これまでRuby on Railsのアプリケーションでは、計測・監視のためにNew RelicAPM (Application Performance Monitoring) ツールとして使っていたのですが、現在New Relicでは公式にはElixirはサポートされていません。*1

そこで今回は、インフラの監視に利用していたDatadogAPMも統合できることを期待して、Datadog APMを利用してみることにしました。

Datadog APMでは単なる集計値のみならず、タイミングの記録にも対応しており、下記のように個々のAPI内の処理内容をフレームグラフとして見ることも可能なため、性能改善には有効そうです。

f:id:NeoCat:20181215201740p:plain

対象アプリケーションの構成

今回、計測対象となるアプリケーションは以下のライブラリを利用しています。

ElixirのWebフレームワークとしてはPhoenixがメジャーですが、今回はPhoenixは利用せず、Cowboyの上にAPIエンドポイントごとのハンドラを書いていくというシンプルな実装になっています。

APMへの対応

ElixirからDatadog APMを利用するのには、コミュニティで開発されている Spandexというライブラリを使用しました。 Spandexは様々なAPMに対応することを想定して開発されていますが、現在のところDatadogのみに対応しています。

導入

まずは、mix.exsに依存ライブラリとしてspandex、および関連ライブラリを加えます。

defdepsdo
  [{:spandex, "~> 2.1.0"},
   {:spandex_datadog, "~> 0.1.0"},  # Datadogアダプタ
   {:spandex_ecto, "~> 0.1.0"},     # Ectoを計測
   {:decorator, "~> 1.2"},
   ...

そして、必要な設定を config/config.exsに追記します。 DATADOG_HOST環境変数は、別途インストールしたDatadog Agentの接続先を指すようにしておきます。通常はlocalhostで良いのですが、コンテナ等で導入した場合はそのコンテナ名とします。加えて、Agentにも DD_APM_ENABLED=trueを渡してTracingのメッセージ(MessagePack形式)を受け取れるようにしておきます。

config :spandex,
  service::sample,
  adapter:SpandexDatadog.Adapter,
  disabled?: {:system, "DD_APM_DISABLED", false},
  env:Mix.env()

config :spandex_datadog,
  host: {:system, "DATADOG_HOST", "localhost"},
  port:8126,
  batch_size:10,
  sync_threshold:100,
  http:HTTPoison

config :spandex_ecto, SpandexEcto.EctoLogger,
  service::ecto,
  tracer:SampleApp.Tracer,
  otp_app::sample

spandex_ecto は性能計測値をログから取り出しているため、Ectoのログ出力先を追加しておきます。

  config :sample_app, MyApp.Repo,
    adapter:Ecto.Adapters.MySQL,
    loggers: [{Ecto.LogEntry, :log, [:debug]}, {SpandexEcto.EctoLogger, :trace, ["db_name"]}],
    ...

最後に、自分のアプリケーションにトレース用のモジュールを作り、アプリケーション起動時に初期化するようにします。

defmoduleSampleApp.TracerdouseSpandex.Tracer, otp_app::sample_appdefmoduleErrordodefexception [:message]
  enddefstart() doConfig.fetch!(:spandex)
    |> configure()
  end# Mixタスク等でAPI外からアプリケーションを利用する場合、これを最初に呼んでトレースを無効化しておくdefdisable() doConfig.fetch!(:spandex)
    |>Keyword.merge(disabled?:true)
    |> configure()
  end# APIでエラーが発生した際は、これを呼び出すことでエラーだったことやそのメッセージを記録するdefreport_error(payload) do
    update_top_span(error: [exception: %Error{message: inspect(payload)}])
  endend
defmoduleSampleApp.ApplicationdouseApplicationdefstart(_type, _args) do...SampleApp.Tracer.start()
    ...

以上で SampleApp.Tracerモジュールを通してAPMの計測が行えるようになりました。

APIの計測の開始と終了

APIの処理の開始時と終了時に、それぞれ SampleApp.Tracer.start_trace(), SampleApp.Tracer.finish_trace()を呼び出します。 type > service > resourceという階層を持つキーワードをつけることで、Datadog APMのWeb UI上でトレースを分類して統計を取ることが可能になります。

加えて、これらの間に SampleApp.Tracer.start_span(), SampleApp.Tracer.finish_span()を呼び出すことで、その中で行われた個々の処理タイミングを記録することができます。この記録をspanと呼びます。

各spanはトレース画面でタイミングや所要時間を見られるほか、個々の集計も行われます。例えばEctoの発行しているクエリのうち、累計で最も時間を消費しているのはどれか?それはどのAPIから呼ばれているか?といった情報を知ることができます。他にも下記の httpなど、メタデータを記録させることもできます。*2

ここではCowboyのミドルウェアとしてこれらの関数を呼び出すことにします。 また、他のミドルウェアでユーザ認証などを行なっているため、その所要時間がわかるよう、 "middleware"というspanを作っておくことにしました。

defmoduleSampleApp.Middleware.TracerdoaliasSampleApp.Tracer@behaviour:cowboy_middlewaredefexecute(req, env) do# APIのトレースを開始するとともに、 middleware の span を作る
    meta = [url: req.path, method: req.method]
    Tracer.start_trace("request", service::sample, type::web, resource: req.path, http: meta)
    Tracer.start_span("middleware", service::middleware, type::middleware)
    {:ok, req, env}
  endenddefmoduleSampleApp.Middleware.Tracer.StartdoaliasSampleApp.Tracer@behaviour:cowboy_middlewaredefexecute(req, env) do# middleware の span を閉じるTracer.finish_span()
    {:ok, req, env}
  endenddefmoduleSampleApp.Middleware.Tracer.FinishdoaliasSampleApp.Tracer@behaviour:cowboy_middlewaredefexecute(req, env) do# APIのトレースを終了するTracer.finish_trace()
    {:ok, req, env}
  endend

これらがをミドルウェアとして呼び出されるようにCowboyに登録します。

:cowboy.start_clear(
    :sample,
    [...],
    %{middlewares: [
        SampleApp.Middleware.Tracer,
        :cowboy_router,
        SampleApp.Middleware.Authorize,  # 各種ミドルウェアが間に入る...SampleApp.Middleware.Tracer.Start,
        :cowboy_handler,                 # ここでAPIのハンドラが呼び出されるSampleApp.Middleware.Tracer.Finish
      ]
    }
  )

以上でアプリケーションの各APIがトレースできるようになりました!

計測対象の追加

Ectoの計測は追加済みですが、他にmemcachedや外部サービスの呼び出しなどをトレースしたい場合、それらの箇所にもspanを追加していきます。 トレース対象の前後で start_span(), finish_span()を呼び出してもいいのですが、

SampleApp.Tracer.span("name", service::sample, ...) do...end

のようにdoブロックで計測対象の処理を書くこともできます。spandex 2.4.0以降であれば、関数を丸ごとトレースする際はデコレータを使って

@decorate trace(service::external_service, type::custom, resource:...)
  deftrace_me() do...end

のように、さらに簡単にトレース対象に加えることができます。

トレースの無効化

計測によるオーバーヘッドは、やはり多少なりともあります。そこで、必要ない時には簡単にトレースを無効化できるよう、環境変数DD_APM_DISABLED=trueを渡せるようにしてあります。これを使って一部のホストだけでトレースを取るといった運用も可能です。

余談ですが、Spandex 2.0.0でトレースを無効化しようとすると例外が発生するというバグがありました。これを修正するPull Requestを送ったところ、すぐにマージしてもらえ、2.1.0では修正されました。些細ではありますがコントリビューションができて良かったです。

結果

集計結果はDatadog APMのWebページ上で閲覧します。サービス全体や個々のAPIについて、呼び出し頻度やレイテンシの分布、消費時間に占めるDBや外部サービスの割合などがひと目でわかります。

f:id:NeoCat:20181215213222p:plain

さらに下部にある個々のAPI呼び出しをクリックすれば、フレームグラフ形式でspanを見られ、さらにそこからspanにつけたメタデータの閲覧へと、細かくドリルダウンしていくことができます。

f:id:NeoCat:20181215201740p:plain

加えて、そのホストのメトリクスも同じ画面内で参照できるため、例えば特定のトレースが遅い時、CPU負荷は高かったのか?といった情報も簡単に得られるようになりました。これはインフラ監視とAPMを統合することのメリットと言えます。

終わりに

この記事では、ElixirのWebアプリケーションのAPIの性能をDatadog APMで計測する方法として、Spandexライブラリの使用方法を紹介しました。

実際に、APMを仕掛けた状態で開発中のアプリケーションのストレステストを行ったところ、N+1クエリなどの非効率な処理がいろいろと見つかり、中でも頻度が高いところを集中的に改善することができました。

それだけに留まらず、DatadogのメトリクスとしてAPMの集計値を利用できるため、個々のAPIの性能に対してアラームを設定したり、Watchdog機能を使って急激に呼び出し頻度が増えたAPIやクエリを自動検出することも可能になり、サービスの運用中にも便利に活用できそうです。

*1:コミュニティによるライブラリは開発されていますが、Phoenixを前提としているものが多いようです。後述の通り、今回の対象アプリケーションはPhoenixを使用していないため、採用は見送りました。

*2:メタデータとして渡せる構造には制限があるようです。SpandexのREADME.mdを参照してください。

開発環境インフラを ECS 移行している話

$
0
0

 この記事は Akatsuki Advent Calendar 2018の24日目の記事です。 前回は id:NeoCatさんのElixirのサーバアプリケーションをDatadog APMでトレースするでした。

はじめに

はじめまして、運用中ゲームタイトルでサーバーエンジニアをしている守屋と申します。 私の所属するチームでは AWS EC2 上でサーバーサイドの運用を行ってきました。サービスリリース当初からの様々な改善の積み重ねの結果、近頃はインフラ障害も少なくなり、安定した運用が実現しています。しかし安定した運用が実現すればサーバーエンジニアの仕事は終わりなのでしょうか?安定しているとはいえ既存インフラには様々な技術的な負債が蓄積されています。我々サーバーチームは既存インフラを設計から見直し、新環境へ全てを移行する一大決心を下したのです。

既存開発環境インフラ構成 

以下に大まかな構成図を示します。*1

f:id:Zepprix:20181222155134p:plain

 サーバーサイドは Nginx & Ruby on Rais 用いたゲーム API サーバー、マスタ等を GUI で管理できる Admin ツールを同一の EC2 上で動かしています。

 ゲームのマスタ & ユーザーデータの格納に RDS 、キャッシュに ElastiCache を利用しており、ゲーム内で収集する各種 log データはアプリ用とは別に log 収集用のEC2 インスタンス( Log Aggregator )を立てており、Fluentd を用いて log DB へ転送しています。開発現場では複数の新規バージョンをチームで分担して同時平行に開発を進めており、新機能の開発や検証を行う環境も複数存在しています。 

デプロイフロー 

f:id:Zepprix:20181224002442p:plainデプロイ用のサーバー上に Capistrano3を用いたデプロイスクリプトを配置しています。Slack から Github社製のチャット bot である Hubotのコマンドを叩くと、コマンド引数として与えた環境名がデプロイスクリプトに渡り、指定先にデプロイが実行される仕組みとなっています。DB Migration もデプロイスクリプトに組み込んでおり、デプロイサーバーから実行する形です。

 デプロイサーバーには他にもマスタデータの Seeding や検証用のダミーデータ生成など様々なスクリプト(ほとんどが Rails の Rake タスク)を配置しており、エンジニア以外でも Slack から Hubot コマンドを叩くことで簡単に実行できるようにしています。

 

実現したいこと

真の Infrastructure as Code の実現

 複数の開発環境は必要性が生じる度にサーバーエンジニアが手動で立ち上げてきた経緯があります。個々のサーバーの設定は構成管理ツールの Chefによる自動化とコード管理が実現していますが、EC2 や RDS インスタンスの立ち上げなどインフラ全体の構成自動化までには手が回っておらず、新規環境の立ち上げには非常に手間のかかる状態となっていました。インフラ全体をコード管理下に置くことで新規構築が容易にできると同時に、新メンバーが既存の構成をコードで把握することができる等のメリットが期待されます。

Feature 毎に環境を立ち上げ可能

 サーバーエンジニアが新機能を実装する際、Git で Feature ブランチを切って作業することがよくあります。しかし実装完了してクライアントとの結合をした上で検証をするには結局、一つの EC2 上にデプロイしなければなりません。よってデプロイしたコードにバグがあった場合、当該サーバーで別機能の検証を行なっていた他メンバーの作業にも深刻な影響を与えることになってしまいます。アプリケーションが動作する環境を例えば Feature ブランチ毎にサクッと立ち上げて検証が完了したら本流にマージして環境を破棄する、みたいな運用を実現したいと考えました。

夢を実現する為のソリューション

Cloud​Formation の導入

 開発環境を構成する全ての AWS リソースをコードで管理し、構築・変更・破棄をコマンドで楽に実行できるようにします。今回は EC2、RDS 等のインスタンスだけではなく、VPC やセキュリティグループ等のネットワーク周りの設定まで全てを Cloud​Formation で作り直します。移行コストは大きいですが、既存設定の整理や見直しの良い機会にもなると考えました。デフォルトでは JSON か YAML で記述することになりますが、 kumogata2を使うと Ruby DSL で便利に書くことができます。

ECS への移行

 Rails アプリケーション、Log Aggregator といったアプリを動かす為の仕組みを Docker コンテナに移行し、全てのコンテナを Docker Compose で単一ホスト上で動かす運用に切り替えます。よって AWS のコンテナマネージドサービスである ECS に移行する形がスムーズです。ECS には EC2 および Fargate で起動する 2 種類のタイプがありますが、Fargate は料金が高く、ホストへの ssh 接続が不可なのでデバッグのやり易さに懸念があり、EC2 起動タイプを採用することにしました。 

既存のインターフェースを変更しないようにする

 今回行う大規模なインフラ構築の最大のネックは既存環境の移行であるという点です。我々が新規インフラ構築作業を行う傍で、既存インフラでは多くのメンバーが開発・検証業務を行なっています。よって新規インフラに移行する際は他メンバーへの負担を可能な限り抑える必要がありました。その為に以下のような方針を打ち立てました。

  • 新 VPC 下にインフラを立て直すが、DNS を切り替えることで既存のエンドポイントを変えないようにする
  • デプロイは今まで通り Slack => Hubot 経由で実行可能にする(当然、その他の Rake タスクも)
  • RDSはコンテナ化しない  *2   

そして出来上がった新インフラ構成案

f:id:Zepprix:20181224003842p:plain ゲーム API サーバー、Admin ツール、Fluentd、Log Aggregator をそれぞれ Docker コンテナ化して単一の EC2 上で動作させ、ECS で管理します。*3

 ゲーム API サーバーと Admin ツールのコンテナは別々ですが、Admin ツールのコードはゲームと同じ Rails リポジトリに入っているので Docker イメージは両者で分ける必要はなく、Docker Compose で Port と環境変数を指定することで起動モードを切り替えて運用します。また RDS、ElastiCache はインスタンスを Cloud​Formation で立ち上げて、既存のデータを移行する方針です。

 アプリを動かす為の仕組みが全てコンテナ化したことで、Ruby や td-agent のインストールなど今まで Chef で 0 から行なっていた EC2 インスタンスのセットアップも大幅に簡略化できることも嬉しい所です。ただしサーバーへのユーザー追加等、最小限の設定は必要なので、この機会に使い古した Chef から Ansibleに乗り換えることにしました。

新しいデプロイフロー

f:id:Zepprix:20181224003918p:plain デプロイは今まで通りデプロイサーバーにスクリプトを配置して、Hubot で実行する形にします。Docker イメージのビルドには AWS のマネージド型ビルドサービスである CodeBuild を使用します。*4

CodeBuild はデプロイコマンドの引数として渡した環境名に対応したブランチのソースコードを GitHub から取得し、ビルドした Docker イメージを Elastic Container Registry(ECR) に Push します。その際に環境名と日時をタグとしてイメージに付与することで、環境によって中身が異なるゲーム API サーバーのイメージを同一の ECR リポジトリにまとめることが可能です。

あとはデプロイサーバーに配置した docker-compose.ymlファイルを利用して ecs-cli composeコマンドでコンテナを起動すれば良いのですが、その前に DB の Migration を Rake タスクで実行する必要があります。以前のようにデプロイサーバー上に Rails リポジトリを Clone しておくのも手ですが、デプロイサーバー上には ECR から Pull された Docker イメージが存在するので、docker runコマンドでコンテナを立ち上げて Rake タスクを実行してしまえば良さそうです。以前よりもサーバー内のディレクトリがスッキリしますね。

Hubot 経由で実行していたその他の Rake タスクも同じ方法でデプロイサーバー上で今まで通り実行できそうです。これで中身を大幅に変更しつつもインターフェースは既存の仕組みを継続するという要件に応えることができます。

実装をどう進めるか

完成した設計を元にタスクを JIRA チケット化してチームで開発を進めています。タスクはかなりざっくりですが、以下の項目が挙げられます。

  • Docker イメージ
    • ゲーム API サーバー
    • Fluentd
    • Log Aggregator
  • CloudFormation テンプレート & Stack
    • VPC、Subnet、Security Group、IAM Role 等のネットワーク・セキュリティ設定
    • ECS、ECR、CodeBuild、RDS、 ElastiCache 等のリソース設定
    • 各開発環境の Stack
  • デプロイフロー
    • CodeBuild
    • ECS
    • Hubot コマンド側の対応
  • Ansible
    • 各サーバーへの User 追加
    • デプロイサーバーへの Docker、ecs-cli インストール
  • クライアントとの結合テスト
  • データ等の移行手順の検討

属人化を防ぐ為、出来るだけタスクをサーバーエンジニアチーム全員に割り振って実装を進める形にしています。手始めに CloudFormation で VPC を立ち上げることで他のメンバーも作業することが可能となりました。

アカツキでは既に複数の PJ にて Docker、ECS での運用が実現しており、他 PJ でのノウハウを活かしながら実装を進めることが出来ています。本記事執筆時点では Sandbox 環境へのデプロイが通るところまで完了していますが、まだまだやるべきことは多いですね。  

まとめと今後の展望

既存のインフラを移行する場合、0 からの環境構築とは違った現場特有の要件に応えていく必要があります。開発環境の移行が完了したら当然、次は本番環境の移行に着手する予定です。インフラ・クラウドに限らず技術は日進月歩、今後も現状に満足せず常により良い環境の構築を目指していきたいと思います。

*1:本記事で紹介するインフラ構成には新・旧どちらにも適宜省略している要素があります。また環境名は実際のものとは異なります。

*2:DB はエンジニア以外のメンバーも Sequel Pro 経由で接続できるようにする必要がある上、データ永続化が必要 & Amazon Auroraの良さが消える等々、コンテナ化するメリットがあまり感じられませんでした。

*3:Log Aggregator は API サーバーと同じホスト上で運用すると Heartbeat UDP Packet が正常に疎通しない問題が他 PJ で発生した為、Staging、Production 環境では別の EC2 インスタンス上にコンテナを配置する予定です。

*4:CodeBuild は e_koma さんによる15日目の記事でも紹介されていますので是非ともご覧下さい。

Go用HTTP APIテストコードジェネレータを開発しているというお話

$
0
0

こんにちは、mizzyです。業務委託でアカツキさんのお手伝いをしています。お手伝いの一環として、aktsk/atgenという、Go用HTTP APIテストコードジェネレータを開発しています。

この記事では、Atgenの概要や開発の背景、今後の予定などについてご紹介します。


Atgen とは

HTTP API Test Code Generatorの略で、HTTP APIをテストするためのコードを自動生成する、Go製のコマンドラインツールです。

YAMLで記述されたテストすべきHTTPリクエスト/レスポンスと、Goで書かれたテストコードのテンプレートから、実際にテストを実行するためのコードを生成します。

atgen/example at master · aktsk/atgenに動かすことができるサンプルがありますので、READMEの通りに動かしてみると、どんなツールなのか掴んでいただけるかと思います。


なぜつくっているのか

Goはその性質上、コードが冗長になりがちです。特に、HTTP APIをテストする場合、リクエストを出してレスポンスをチェックする、という同じような記述のテストコードをたくさん書くことになり、更に冗長になってしまいます。

コードが冗長になると、コピペも多くなりますが、コピペした後に修正すべき部分の修正が漏れることもあります。テストが失敗すれば修正漏れに気づくこともできますが、通ってしまうと漏れに気づかず、誤った内容でテストしているがそれに気づけない、ということになりかねません。

また、テストコードが冗長だと、全体の見通しが悪くなり、どのエンドポイントがテストされていて、どのエンドポイントがテストされていないのか、把握するのが難しくなります。

そこで、同じようなコードを書く手間を省き、コピペによるミスを防ぎ、APIエンドポイントのどこまでをカバーできているのかを把握しやすくするために、Atgenを開発することにしました。


開発にあたって検討したこと

このツールが、なぜこのようなつくりになっているのか、はコードを読んでもわからないですし、作者の自分も忘れそうなので、ここに記録しておきます。

YAMLにしたがってテストを実行するのではなく、テストするコードを生成するのはなぜか

ツールの方向性として、YAMLに基づいてテストコードを生成するのではなく、直接テストを実行する、という方向性も考えました。しかし、一度テストコードに落とし込んでから実行することで、テストが失敗した場合に、該当するコードを直接読むことができ、原因を調査しやすいだろうと考え、テストを直接実行するツールではなく、テストコードを生成するツールにしました。

テンプレート処理にtext/templateを使わずにAST書き換えを行っているのはなぜか

AST書き換えをせずにtext/templateを使った方がツール自体の実装は簡単です。しかし、{{ .Var }}のようなtext/template記法がテンプレートコード中に入ると、Go的には不正な構文となるため、go fmtでエラーになるなど、ツールやエディタの言語サポート機能を活かせなくなり、テンプレートコードを書く時ににとても不便です。なので、 text/templateは使わずにAST書き換えで処理をする、という形にしました。

あと、私がAST書き換えを行うようなツールを一度作ってみたいと思っていたから、という理由もあります。

テスト対象のリクエスト/レスポンスの定義にOpenAPI準拠のYAML/JSONを使わないのはなぜか

Atgenを導入しているプロジェクトでは、swagger.yamlでAPIの仕様が定義されているので、これをテストの定義にも使い回せないか、と最初は考えました。しかし、仕様の記述とテストの記述は似ているようで違っていて、特に以下の点が異なると考えています。

  • リクエストやレスポンスのパラメータの違い
    • 仕様ではパラメータの型が定義されるが、具体的な値は定義されない
    • テストでは具体的な値を記述する必要がある
  • コンテキストの有無の違い
    • 仕様では各リクエスト/レスポンスが独立した形で記述される
    • テストでは、このパラメータでPOSTしてから、GETするとこういうパラメータが返ってくる、みたいな形で、複数のリクエスト/レスポンスの関連性を記述する必要がある

このような違いがあるため、OpenAPI準拠のYAMLでテストの定義までカバーするのは無理がありそうだ、と判断して、無理に寄せることはせずに、あえて別のフォーマットにしています。

また、Go用のツールなので、Goの慣習にしたがい、Goの機能を活かしたコードを生成できるようなフォーマットにしたい、という理由もあります。


実戦投入してみての所感

既存プロジェクトのテストコードとほぼ同等なコードをこのツールで生成できるようになったので、生成したテストコードをCircleCIで回すようにしてみました。実践投入してまだ間もないですが、現在のところの所感は以下の通りです。

  • テスト定義をYAMLで記述することで、テスト項目全体の見通しがよくなり、APIエンドポイントのどこまでカバーされているのか、把握しやすくなる。
  • 見通しがよくなることで、レビュアーがレビューしやすくなり、テストの間違いや漏れを見つけやすくなる。
  • 反面、前処理などテストによって微妙に処理が異なるところがあり、ひとつのテンプレートで吸収しようとすると、ifでの条件分岐が多くなり、コードの見通しが悪くなる。
  • 書き換えのためのルールを把握してテンプレートコードを記述しないといけないので、普通にテストコードを書くよりも面倒。
  • このように、テスト項目のメンテナビリティは向上するが、コードのメンテナビリティは低下する。
  • が、テストは書くことよりもメンテナンスすることの方が大変なので、トータルで見ると運用コストを下げてくれそう。
  • テスト項目のメンテナビリティを保ちつつ、コードのメンテナビリティをいかに下げるか、という方向でツールを改善していくのが今後の課題。

今後の予定

まだツールとしては発展途上で、やることはたくさんありますが、以下の様な方向で考えています。

  • ドキュメントの充実
    • 特に書き替えルールがわかりにくいので、その辺りを重点的に。
  • 使い方をわかりやすくする
    • YAMLだけでできる範囲を広げ、できるだけコードを書く量を減らす。
  • OpenAPI準拠YAML/JSONとの連携
    • OpenAPI準拠YAML/JSONとテスト定義YAMLを突き合わせ、テストされてないエンドポイントを出力する、といった機能

または、もっと違う方向性で実装しなおした方が良いのでは、とも考えています。というのも、Atgenは汎用的に使えるようにするため、テスト対象のAPIサーバのコードには一切関知しない、というスタンスで実装しています。ですが、APIサーバのコード内で定義されている型などをうまく利用した方が、よりわかりやすい形でテストコードが書けます。とは言え、テストコードジェネレータが特定のAPIサーバのコードに依存してしまうと、汎用性が失われてしまいます。これを解決するために、テストコードジェネレータではなく、テストコードジェネレータの開発を支援するライブラリとして実装する、といった方向性もあるのではないか、とぼんやりとですが考えています。


謝辞

ツールの実装にあたって、tenntenn さんによる Go AST に関する Qiita 記事motemen さんによる GoのためのGoがとても参考になりました。この場を借りてお礼を申し上げます。

【LT会】Akatsuki Geek Live開催レポート!

$
0
0

こんにちは、エンジニア採用担当の花田です。

この度、2/22(金)に学生向けLT会「Akatsuki Geek Live」を開催いたしました!

今回が初めての試みでしたが、30名を超える学生の方に集まっていただき、最高のLT会となりました!!この記事では、その様子を紹介いたします。

 

「Akatsuki Geek Live」とは...

学生エンジニアと、アカツキエンジニアが登壇するLT会です。今回は学生4名、アカツキメンバー4名の計8名が発表しました。その後、参加者全員で懇親会を実施し、交流の場を持ちました。

 

▼詳細はこちらから

aktsk.connpass.com

 

#なぜLT会を開催するに至ったのか

これまで学生の方にアカツキを知ってもらう機会として、会社説明会と座談会を開催していました。座談会での質疑応答は活発ではあったものの、より深くアカツキの技術やエンジニアメンバーについて伝える形にしたいと思っていました。

また、将来エンジニアとして活躍する学生のみなさんに登壇いただくことで、成果発表の機会や、他の学生の取り組みにふれて刺激し合ったり、同じ領域に興味を持っている方とのつながりの場を創ることで、可能性が開花するきっかけとなれば、という想いから企画しました。

 

#当日の様子

初めての開催ということもあり、参加者が集まるか心配しましたが、ふたを開けてみれば2度の増枠に。当日は32名が参加してくれました。また、学年不問で募集したため、4月からアカツキに入社する内定者や、20卒の内定者やインターン生、就職活動を迎える21卒の学生など多岐にわたるメンバーが集まってくれました。登壇順はくじ引きで決め、早速スタートです!

 

▼1人目:@sachaosさん(アカツキ)

「Goの静的解析ツールの作成と活用」

1人目は、アカツキメンバーから!Goによる静的解析のしやすさを発表してくれました。

f:id:kenji-hanada:20190227182712j:plain

発表資料

speakerdeck.com

 

▼2人目:@菱谷さん(アカツキ)

「今風トゥーンシェーディング」

2人目もアカツキから、新卒1年目の菱谷さんが、トゥーンシェーディングへのこだわりを熱く語ってくれました!

f:id:kenji-hanada:20190227183854j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

▼3人目:@tkhatotoさん(学生)

「Hack on Slash on Terminal」

3人目は学生枠からtkhatotoさん。会場から「このスライド見ていて楽しい!」と視覚的に楽しませてくれる発表でした!

f:id:kenji-hanada:20190227184515j:plain

発表資料

Coming soon

 

▼4人目:@kawasin73さん(学生)

「俺はビッグエンディアンでテストがしたいんだ!」

3人目は学生枠からkawashin73さん!タイトルからも伝わってくる通り、掴みバッチリのキーワードから熱く想いを叫んでくれました^^

f:id:kenji-hanada:20190227185903j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

 

▼5人目:@大嶋さん(アカツキ)

「お父さんが教えるプログラミング教育」

アカツキから、子育て中のパパエンジニアとして、プログラミングの楽しさを伝えたいという想いが詰まっていました!特に「プログラミング的思考を料理で教える」というパートは非常にわかりやすく、参加者の多くがうなずきながら聞き入っていました。

f:id:kenji-hanada:20190227190634j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

▼6人目:@july1997さん(学生)

「MMOの作り方」

学生枠july1997さんがMMOの作り方というテーマで、クライアント、サーバ両方の観点から発表してくれました!

f:id:kenji-hanada:20190227192150j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

 

▼7人目:@Zepprixさん(アカツキ)

「Docker & ECSで構築するゲームアプリサーバーの話」

アカツキから新卒2年目のZepprixさんの発表。Docker & ECSを活用して管理コストを下げる話をしてくれました!

f:id:kenji-hanada:20190227192457j:plain

発表資料

speakerdeck.com

▼8人目:@acomaguさん(学生)

「RDF/OWLで始める人生イベントソーシング」

トリを務めるのは学生枠よりacomaguさん!RDF/OWLの「ゆるイイ!」理由を熱く語ってくれました。

f:id:kenji-hanada:20190227193151j:plain

発表資料

speakerdeck.com

 

熱のこもった8名の発表はあっという間に終わりました!

今回、登壇いただいた学生の方には、アカツキからプレゼントを贈り、続いて懇親会へ。

発表に刺激を受けたメンバーからの声や、同じ技術領域に興味を持っているメンバー同士での交流など、大いに盛り上がり、会を終えました。

f:id:kenji-hanada:20190228114007j:plain

 

参加者のみなさん、お疲れ様でした!

次回は4/26(金)に開催いたします!今回参加した方も、初めての方も大歓迎ですので、熱い想いを持ったみなさんにお会いできることを楽しみにしています!

 

▼次回予約はこちらから

aktsk.connpass.com


カスタマーサポートに便利なMariaDB Spider エンジンを、Docker上に移設して保守も便利にする

$
0
0

はじめに

ゲームの運営では日々お客様から「ログインが出来なくなってしまった」「受け取れるはずのアイテムが受け取れなかった」などのお問い合わせをいただきます。

そのお客様が仰ったことが本当に発生したかどうか、あるいは本当とすれば原因は何かを考えるために、私達はそのお客様のデータや操作ログをサーバーのデータベースに保存しております。

さらにはゲームのイベント開催情報やカードのステータスなど、運営に関わるデータ(マスターデータ)と横断的に照らし合わせた上で、判断しております。

ここではそんなカスタマーサポートに役立てているMariaDB Spiderエンジンの紹介と、今回それをDocker上に移設して保守も便利にした話を書こうと思います。

MariaDB Spider エンジンとは

Spiderエンジンはデータベースのエンジンでありながら、内部にデータを保存することは行いません。

代わりに、テーブル構造とデータのあるホストを指定すると、Spiderエンジンのテーブルでクエリを実行するたびに指定したホストからデータを取得してくれます。

Spiderエンジンについての詳細はこちら

さらにはカラムの値によってデータベースの接続先を振り分けることも可能なため、1つのSpiderエンジンのテーブルから、水平分割されたデータベースからクエリに合わせて自動的に適した場所にアクセスすることも可能になります。

なぜSpiderエンジンがカスタマーサポートで便利なのか

私達のチームではデータベースにかかるインフラの負荷上、マスターデータやユーザーデータおよびログを1台のサーバーに集約することが出来ません。

さらはユーザーデータやログについては、1台で全ての負荷を受け止めることは出来ないため、さらにユーザーごともしくはテーブルごとにそれぞれ複数台に分割してデータを管理しております。

一方で様々なデータを横断的に検索するカスタマーサポートでは、もちろん出来ればデータの内容に合わせて手動で参照先を切り替える面倒は省きたいですね。

そこで、一つのSpiderエンジンから複数に散らばった必要な全てのデータを取得できるよう構築することがカスタマーサポートに大きく役立ちます。

Docker上で使用する理由

一方でSpiderエンジンはややマイナーなエンジンであるため、AWSのRDSから作ったデータベースにはインストールされておりません。 そのためAWSを使用している場合は、RDSを使うのは諦めてEC2インスタンスの上にMySQLサーバーを立ち上げた上で、Spiderエンジンをインストールする必要があります。

従来はSpiderエンジンを直接EC2インスタンスにインストールしていましたが、以下の問題を抱えていました。

  • データ構造や設定が管理されていないので、サーバーの立て直しが困難になってしまった。
    • その結果、EC2インスタンスのOS等のバージョンアップがしづらいので古くなってしまった。
  • アプリケーションのバージョンアップに伴いデータ構造が変わる際は、Spiderエンジンのデータベースにも都度合わせて手動で差分クエリを発行して変更する必要がある。そのためミスや抜け漏れによって実データベースと構造の差異が発生しやすい。
    • 特に使用頻度の低い場所については適切なアップデートがされなかった結果、過去に発生した構造の差異を埋めるのも困難な状態になってしまった。

そこで、今回はOS等のバージョンアップのためサーバーを立て直すのと合わせて、今後保守を行いやすいようDocker化を行うことにしました。

実装

まずはDockerfileの中身から見ていただけたらと思います:

FROM mariadb:10.3-bionic

RUN apt-get update && apt-get -y install \
  ssh \
  mariadb-plugin-spider \
  gcc \
  make \
  libssl-dev \
  libmariadb-dev

RUN cp /usr/share/mysql/install_spider.sql /docker-entrypoint-initdb.d/00_install_spider.sql

COPY 01_init.sql /docker-entrypoint-initdb.d/
COPY create_tables.sql /root/scripts/

COPY spider.cnf /etc/mysql/conf.d/
COPY mysql_init.sh /usr/local/bin/

RUN sed -i -e "s/exec \"\$\@\"/exit 0;/" /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["mysql_init.sh"]

やっている内容としましては、

1. Spiderエンジン・MariaDB起動に必要なライブラリを追加します
2. /docker-entrypoint-initdb.d/に、Docker起動後に実行したいSQL文のファイルを指定します
  • まず、Dockerイメージの中にSpiderをインストールするためのSQLファイル /usr/share/mysql/install_spider.sqlがあるので、それを移します。
  • またデータベース起動時に実行させたいSQLファイルも合わせて作成し、移します。(今回は例として 01_init.sqlに起動時に必要なユーザーやデータベース等の設定を記述します。)
    • なお、テーブルの追加 (create_tables.sql) については後述する理由(「ハマったポイント」を参照)から別の場所に移して別のタイミングで実行させます。
  • ファイル名の昇順に実行されるため、頭に数字等を入れると順序が整理しやすいかもしれません。

01_init.sqlの中身の例としては、以下のとおりです。

/*データベースの追加*/
CREATE DATABASE {Spider側のデータベースの名前};
/*ユーザーの追加*/
CREATE USER `{作成したいユーザー名}`@'%' IDENTIFIED BY '{作成したいパスワード名}';
GRANT SELECT, SHOW VIEW ON {作成したデータベース名}.* TO '{作成したユーザー名}'@'%';
/*接続先の追加*/
CREATE OR REPLACE SERVER {サーバー名} FOREIGN DATA WRAPPER mysql OPTIONS(HOST '{リモートのホスト名}', DATABASE '{リモートのDB名}', USER '{リモートのユーザー名}', PASSWORD '{リモートのパスワード名}', PORT 3306);
3. spider.cnfを設置します。

spider.cnfの中身の例は以下のとおりです。適宜ご利用の状況に合わせて書き換えてください。 各パラメータのドキュメントはココにあります

[mysqld]
table_open_cache=6600
max_connections=100
general_log=ON
general_log_file=/var/lib/mysql/mysql-running.log
slow_query_log=ON
slow_query_log_file=/var/lib/mysql/mariadb-slow.log
tmp_table_size=167772160
max_heap_table_size=167772160
open_files_limit=65535
4. Dockerのエントリポイント用のファイルを作成して指定します。

Dockerfile の例では、 mysql_init.shがそれに当たります。理由と詳細な中身については後述の「ハマったポイント」を参照してください。

5. 最後に、 docker-compose.ymlを設置します。

docker-compose.ymlの例は以下のとおりです。

version: '2'
services:
  db:
    container_name: container_name
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: test
    ports:
     - "3306:3306"

ハマったポイント

また一方でまだまだ発展途上のエンジンですので、以下のようなエラーも発生してしまいました。 私もまだまだ力不足ゆえ根本解決には至りませんでしたが、回避策を記したいと思います。

1回MySQLが再起動すると、SPIDERでパーティション分割されたDBを読み込めなくなってしまう。

デフォルトのエントリーポイントである/docker-entrypoint.sh mysqldを実行すると、 /docker-entrypoint-initdb.d/以下のSQLファイルを実行した後に一回MySQLを再起動してしまいます。

それによって再起動した際に、パーティション分割されたDBを読み込めなくなってしまう問題があるため、/docker-entrypoint-initdb.d/にてテーブル作成SQLを書いてしまうと、正しく読み込まれなくなってしまう問題があります。

そこで、今回はDockerfileのエントリポイントを以下のファイルにすることで回避しました。(今回の例では mysql_init.shとしております。)

mysql_init.shの中身の例

#!/bin/bash
/docker-entrypoint.sh mysqld

/etc/init.d/mysql start
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h localhost < /root/scripts/create_tables.sql

while sleep 30; do
   ps aux | grep mysqld | grep -q -v grep
   PROCESS_1_STATUS=$?

  # If the greps above find anything, they exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit 1
  fi
done

内容としてはテーブル作成など再起動後に行いたい処理(この例では create_tables.sql)をその後別途行うようにエントリーポイントのファイルを上書きします。

その後はこの例ですと30秒毎にプロセスの死活監視を行い、もしプロセスが終了してしまった場合は停止させます。 こちらの記事が参考になります

また create_tables.sqlの中身の例は以下のとおりです。

USE {Spider側のデータベースの名前};
CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL DEFAULT 0,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=SPIDER DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='table "users"'
PARTITION BY RANGE (`id`)
(PARTITION `p1` VALUES LESS THAN (200000000) COMMENT = 'server "{サーバー名}"' ENGINE = SPIDER,
 PARTITION `p2` VALUES LESS THAN (300000000) COMMENT = 'server "{サーバー名}"' ENGINE = SPIDER,
...)

{サーバー名}の部分には、先程の 01_init.sqlにて CREATE OR REPLACE SERVERコマンドを実行した時に指定した名前が入ります。

以下の条件で、UNION ALLが正常にできないケースがある(カラムがずれる、CASE文を挿入するとエラーが発生するなど)

  • SPIDERエンジンのテーブルに対して、SELECT文に固定値もしくはcase文を入れた場合
  • かつ、partitionを使用していないテーブルに対して実行した場合

これについては、パーティションを必要としない(水平分割していない)テーブルについても、パーティションを用意することで回避しました。

Dockerを使用した効果

Docker化したことによって、課題であったサーバーの立て直しのしづらさと実データとの差異は無事解消することが出来ました。

これは実際にはデータを扱っていないことを活かして、更新する際は単にDockerイメージを自動で一から作り直してDockerコンテナを差し替える運用にした結果、以下のことが容易に出来た要因が大きいと考えます。

  • 実データと構造の差異が発生しても差分を考慮して都度クエリを発行せずに、 create_tables.sqlの中身を実データベースの show create tablesの内容をベースに生成してDockerイメージを差し替えることで対応できる
  • その結果、別途スクリプトで自動化してDockerイメージを作り直すのと同時に実データベースの変更を反映させることも可能になった。

一般的にはマネージドでないサービスでのデータベースの管理はDockerを使っても大変そうかと思いましたが、こと実データの取り扱いがないSpiderエンジンでは、Dockerと合わせることで想像以上に保守が楽になりました!

アカツキインターン参加記

$
0
0
エンジニアインターンとして二週間アカツキで働いたnkzさんの体験記をお届けします。初めてのインターン、そして初めての実践的な開発に関わったということでしたが、どのような経験をされたのでしょうか。その様子をレポートいただきます。

ご挨拶

初めまして。nkzです。この度アカツキで、あるモバイルゲームのサーバサイドエンジニアとしてインターンをさせていただきました。趣味は競技プログラミングでそれ以外の開発経験はほとんどありませんでした。開発経験の無い競プロ勢がインターンに行ったらどうなるか?という一つのモデルケースにしてもらえれば幸いです。期間としては二週間ちょっと、開発環境はRuby on Railsでした。

インターンが始まるまで

アカツキのインターンに行くことを決めたのがインターン始まる二週間前とかで準備する期間はあまりありませんでした。一応メンターに「Rails Tutorialを最低7章までやっておいて」と言われたので、7章までやりました。
Webアプリケーションを作った経験はほぼ無くて、N予備校のプログラミングコースでNode.jsのExpressというフレームワークを使ってなんかやったくらいなんですが、なんかそれに比べるとかなり使いやすい印象を受けました。何となくRailsが流行っている理由が分かりました。

初日

インターンに伴うオリエンテーションや社内ツールなどの設定をやっていました。この日はメンターが不在だったので、フリースペースで人事の方とお話ししながらまったり過ごして早めに帰りました。

環境構築 〜 最初の課題(N+1問題)

二日目からメンターと顔合わせをして、まずは環境構築から始めました。ドキュメントを読みつつメンターに教えてもらいつつやりました。私が勝手にmysqlの新しいバージョンをインストールしたせいで、他の箇所でエラーが出たりして、環境構築は辛いと思いながら何とかできました。

そして最初の課題は「あるAPIでN+1問題が起こってそうだからそれを解決してみよう」というものでした。

「N+1問題」は有名な問題らしいのですが、私は「そもそもN+1問題とは……?」という状態でした(名前は何となく聞いたことがある)

幸いにも有名な問題なのでググるとたくさん解説ブログなどが出てきてくれて、以下のようなブログが参考になりました。
ruby-rails.hatenadiary.com

感覚としてはデータベースのサイズをN, クエリの数をQとするとN+1問題が起こっている状態ではO(NQ)くらいかかっている状態で、それをO(N)になるように修正したい、ということなんだろうと解釈しました(合ってるかな…?)

ともかくグーグルによってN+1問題とは何かは分かりましたが、次にそれがどこで起こっていてどう修正すればいいのか、ということを突き止めていかなければいけませんでした。

プロジェクトのソースコードは大規模でRails Tutorialで触ったようなサンプルアプリケーションとは比べ物にならないくらいファイルが多くて、まず「ソースコードを読む」ことすら困難でかなり苦労しました。

ようやく「ここかな?」と思うところを見つけてコードを書き直してみたものの、メンターに「そこじゃないよ」と言われてしまい……最終的にはお手上げ状態になってしまい、ソースコードやログの読み方を教えてもらいつつ「ここを直せばN+1問題が直るね」と教えてもらって「なるほどな〜」となってこの課題は終わりました。私は何も出来ませんでした…

とても勉強にはなりましたが、自力では何も出来なかったので落ち込みました。「まぁ何の知識も無い状態からスタートしてるしこういうもんだよね」という感じで切り替えて行くことにしました。ここまでで三日経ちました。

二つ目の課題(社内ツールのビューを作る)

二つ目の課題は「シナリオチームが使っている社内ツールがあって、変換部分は既に作ってあるから操作するためのビューを作ってください」というものでした。この辺りで私が想像していたサーバサイドエンジニアとは少し違った課題になりつつありますが、そういう仕事もやるんだという感じでやっていきました。

前回見たプロダクトのコードよりもかなり小規模で、Rails Tutorialをやったくらいの人間にはちょうどよかったです。また一から新しいものを作るというより、既存のコードを参考にしながら作れる部分がかなり多くてそれも良かったです。

またここで初めてRSpecというテストフレームワークを使ってテストを書きました。「ブラウザの操作をシミュレートして期待する動作をしているか?」みたいなこともヘッドレスブラウザを使って簡単に実装できるらしく、凄いと思いました。テストを書くのは大変だけど面白いと思いました。

この課題ではたまにメンターに助けてもらうこともありつつ(turbolinkのせいでCSSが当たらない、テストの文法が間違っていてブラウザの挙動がおかしいなど)、自分で調べたり考えたりしながら進められることも多く最終的にPRをレビューしてもらってOKを出してもらって、達成感がありましたし少し自信がついたので良かったです。自分のレベルに合った課題を割り振ってもらっているおかげですが。ここまでで五日経ちました。

三つ目の課題(社内ツールの機能修正)

次の課題は前回の社内ツールの機能に不具合があるのでそこを修正するというものでした。

この課題はそんなに難しい点は無かったので割とサクサク実装することが出来ました。先頭にBOMが付いている文字列と付いていない文字列を同値比較していてデバッグ出力してもぱっと見同じに見えるのになぜfalseが返ってくるんだ…?というところで若干ハマりそうになりましたが…

メンターには「ファイルを直接触るようなテストは環境に依存する可能性があるので、ファイルに書き出す文字列を返すような関数を作ってそれをテストする形にしたほうが良い」ということを教えてもらったりしました。

あとこの辺りからコミットメッセージを以下のgistを参考にしながら英語で書くように努めました。(あまり悩みすぎるところでは無いと思っていたので文法とか適当ですが…)
[転載] gitにおけるコミットログ/メッセージ例文集100 · GitHub

ここまでで七日経ちました。

四つ目の課題(社内ツールの入力フォームを作る)

四つ目の課題は手がけていた社内ツールの入力フォームを作って入力された値のバリデーションをしてごにょごにょやるというものでした。これがインターンの課題で一番大変でした。

とりあえず最初はモデルを作らずに入力フォームのビューを作ってバリデーションはそのままparamsに入っている値を直接見て有効な値で無かったらエラーメッセージを表示させて…みたいな方法でやろうとしていました。モデルを作らなくていいと思った理由は入力フォームの値をDBに保存したり読んだり、みたいな操作が必要無いのでモデルを作らないほうがいいのかな?と思ったからです。しかし実装している途中で「これいちいち空チェックのバリデーションを自分で実装するのは筋が悪い気がする…ActiveRecordを継承すればその辺楽になるのに…」と思って、DBにアクセスせずにモデルを作るってありなのかな?と思って調べてみると…ありました。

qiita.com

どうやら include ActiveModel::Model と書けばいい感じにバリデーションのメソッドを使えたりViewに紐付くように出来たりするようです。

というわけでモデルを作ってバリデーションはそれに任せる感じにしたらだいぶいい感じになりました。

次にやりたいのは「フォームの入力に失敗した時にフォームに入力した値を保持した状態でリダイレクトさせる」ことでした。これもなかなかいい実装が出来ず最初は失敗した時に入力フォームの値をセッションに一時的に保存してレンダーする時にその値を埋めてセッションに保持した値を消して…みたいなことをしていて「うーん」という感じでした。これもメンターに「いい書き方無いですかね…」と相談したところ、リダイレクト先にフォーム情報をクエリ文字列として渡すという方法でシンプルに解決することができました。

他にも色々メンターやWeb業界で働いていた人にもレビューをもらって様々な学びがありました(form objectの話とか)。また色々ハマったこともありました(form_withの挙動とか)。振り返ってみるとこの課題が一番苦労したなぁ…という感じです。その分達成感も一番あって自分でも頑張ったと思います。

ここまでで十一日経ちました。

五つ目の課題(社内ツールの機能追加)

インターンも終わりに近づいて残すところ後二日となりました。最後は手がけていたツールの機能追加…というか機能拡張ですかね。今まではViewを弄っていましたが今回はModelを作る感じでした。「後二日で終わるのかな…」という感じでしたが、ソースコードを読んでいると割と既存のコードを流用できる部分が多くてほとんどコピペして後は少し修正してテストを書くぐらいの作業で特にハマるポイントもあまり無く無事終わらせることができました。

開発以外にやったこと

以上がインターンでやった開発の内容です。インターンの仕事内容としては上記の開発がほとんどですが、それ以外にも色々なことを体験させてもらったのでずらっと書いていきます。

朝会(あさかい)

インターンは10:00出社なのですが、毎日10:05から朝会というものがありました。これはチーム全体で5分程度の時間を取って全体に共有したいことなどを伝える時間です。だいたいプランナーさんが売上状況とかゲームがどれくらい遊ばれているかとかイベントの状況などを共有することが多かったです。

昼会(ひるかい)

毎日14:30からは昼会というものがありました。朝会はチーム全体での共有でしたが、昼会は開発チームで集まって15分程度の時間を取って共有事項を伝えたり、「今まで自分が取り組んできたタスク・これから取り組んでいくタスク」を全員が一言二言で共有するという時間です。エンジニアは自分の開発にかかりきりになるとどうしても周りが見えづらくなってしまうことがあると思いますが、この時間があることでみんながどういうことをやっているのかを把握できるので良い取り組みだと思いました。

エンジニアミーティング

隔週火曜日17:00からはエンジニアミーティングがありました。これはチーム単位では無く社内全体でエンジニアが集まって外部から招いた人の話をしたり、インターン生の紹介をしたり、自分が作ったツールをみんなに紹介したり…という時間です。最初のエンジニアミーティングではセキュリティに強い人を招いたお話があってCTFの可視化の話があったり、バイナリかるたとかアセンブラ短歌という世界があるという話を聞いたりしてよく分からなかったですが「すげー」と思いました。

1on1

毎週火曜日は30分程度のメンターとの1on1がありました。業務中はなかなか落ち着いて話す時間も無いのでこういう時間を設けてゆっくり話をする、みたいな感じです。特に大層な話をしたわけでは無いですが、インターンのフィードバックを少しもらったりアカツキという会社について聞いたりその他は雑談をしていました。私は競プロをやっているのでその話をしていたら、この前マラソン系のコンテストで出た問題がメンターが10年くらい前の高専プロコンで取り組んだ問題と実はほぼ同じだった、という面白い話を聞けたのがよかったです。

インターンの成果報告

エンジニアのインターン生は私以外にも結構いました。インターン生は最終日に成果報告をすることになっているので、私も他のインターン生の発表を聞きに行っていたのですが、AWSの環境構築をガッツリやっている人やゲーム内のミニゲーム(正の得点を得ることすらめちゃくちゃ難しい)を作っている人の話を聞いて、みんな凄いレベル高い…と思って聞いていました。刺激を受けました。

ランチとか飲み会とか

たまにメンターが他の人を誘って一緒にランチに行ったり、インターン生が卒業するときに一回大々的に飲み会が行われたりしました。ランチでは他のプロジェクトチームの話を聞いたりすることができました。インターン卒業飲み会でアイマスにめっちゃ情熱を注いでいるインターン生がアイマスをめちゃくちゃ推してくれたのでちょっと見てみようと思いました。

インターンで感じたこと・学んだこと

ゲームはいろんな人が協力しあって出来ている

当たり前っちゃ当たり前ですが、実際みんなと同じフロアで働くことでより強くそれを感じることができました。エンジニアだけでは無く、プランナーさんが企画したりディレクションをしてくれたり、シナリオを作ってくれる人、絵を描いてくれる人、音を作ってくれる人、モーションを作ってくれる人、検証をしてくれる人……様々な人の協力で一つのゲームが作られていてそれって凄いことなんだ、と感じました。

アカツキの働く環境はめっちゃ良い

アカツキはオフィス環境作りにもかなりこだわりを持たれていて、そのおかげでみんながストレス無く働ける環境になっていると感じました。靴を脱いで素足で仕事ができるとか、各階におしゃれなカフェっぽい休憩スペースがあっていつでも自由に休めるとか、オフィスに緑があったりして心が安らぐとか(?)。オフィスにいるのが苦痛になってしまったら仕事も辛いものになってしまうと思いますが、オフィスがおしゃれで居心地が良いのでそういうことは全く無く非常に良かったです。ただトイレに行くときに靴を履かなきゃいけないのがちょっと面倒ですが…

またオフィスだけでは無く、一緒に働く人たちも皆それぞれ違った個性を持ちつつも良い人が多いんだろうという印象を受けました。今回のインターンでは他の人と一緒に仕事をするという感じでは無かったので、あくまで普段のオフィスの雰囲気を見て、という感じですが。話し合うことはたくさんあるだろうし、ときにはすれ違いなどもあると思いますが、ギスギスした感じでは無く笑いもありながら和やかな雰囲気で皆さん仕事に取り組んでいました。

終わりに

始めにインターンのお誘いをいただいたときは正直かなり悩んでいました。行った方が良いんだろうな…と思いつつ不安な部分も大きくて「行きます」と言った後も「やっぱり辞めとけば良かったかな…」と考えたりしていました。

それでも実際に来てみると、やっぱり大変なことやしんどいこともありましたが、それ以上に良い環境で働けて学ぶことや感じることも多くてトータルで見ると「来て良かった!」と思えるものでした。この度インターンでお世話になった人事の方やメンターの方、一緒に働いてくれた方々には本当に感謝しています。

それでは長くなりましたが、ここまで読んでくださってありがとうございました。

アカツキインターンで体験したこと・感じたこと

$
0
0
エンジニアインターンとして二週間アカツキで働いたnkzさんの体験記をお届けします。初めてのインターン、そして初めての実践的な開発に関わったということでしたが、どのような経験をされたのでしょうか。その様子をレポートいただきます。

ご挨拶

初めまして。nkzです。この度アカツキで、あるモバイルゲームのサーバサイドエンジニアとしてインターンをさせていただきました。趣味は競技プログラミングでそれ以外の開発経験はほとんどありませんでした。開発経験の無い競プロ勢がインターンに行ったらどうなるか?という一つのモデルケースにしてもらえれば幸いです。期間としては二週間ちょっと、開発環境はRuby on Railsでした。

インターンが始まるまで

アカツキのインターンに行くことを決めたのがインターン始まる二週間前とかで準備する期間はあまりありませんでした。一応メンターに「Rails Tutorialを最低7章までやっておいて」と言われたので、7章までやりました。
Webアプリケーションを作った経験はほぼ無くて、N予備校のプログラミングコースでNode.jsのExpressというフレームワークを使ってなんかやったくらいなんですが、なんかそれに比べるとかなり使いやすい印象を受けました。何となくRailsが流行っている理由が分かりました。

初日

インターンに伴うオリエンテーションや社内ツールなどの設定をやっていました。この日はメンターが不在だったので、フリースペースで人事の方とお話ししながらまったり過ごして早めに帰りました。

環境構築 〜 最初の課題(N+1問題)

二日目からメンターと顔合わせをして、まずは環境構築から始めました。ドキュメントを読みつつメンターに教えてもらいつつやりました。私が勝手にmysqlの新しいバージョンをインストールしたせいで、他の箇所でエラーが出たりして、環境構築は辛いと思いながら何とかできました。

そして最初の課題は「あるAPIでN+1問題が起こってそうだからそれを解決してみよう」というものでした。

「N+1問題」は有名な問題らしいのですが、私は「そもそもN+1問題とは……?」という状態でした(名前は何となく聞いたことがある)

幸いにも有名な問題なのでググるとたくさん解説ブログなどが出てきてくれて、以下のようなブログが参考になりました。
ruby-rails.hatenadiary.com

感覚としてはデータベースのサイズをN, クエリの数をQとするとN+1問題が起こっている状態ではO(NQ)くらいかかっている状態で、それをO(N)になるように修正したい、ということなんだろうと解釈しました(合ってるかな…?)

ともかくグーグルによってN+1問題とは何かは分かりましたが、次にそれがどこで起こっていてどう修正すればいいのか、ということを突き止めていかなければいけませんでした。

プロジェクトのソースコードは大規模でRails Tutorialで触ったようなサンプルアプリケーションとは比べ物にならないくらいファイルが多くて、まず「ソースコードを読む」ことすら困難でかなり苦労しました。

ようやく「ここかな?」と思うところを見つけてコードを書き直してみたものの、メンターに「そこじゃないよ」と言われてしまい……最終的にはお手上げ状態になってしまい、ソースコードやログの読み方を教えてもらいつつ「ここを直せばN+1問題が直るね」と教えてもらって「なるほどな〜」となってこの課題は終わりました。私は何も出来ませんでした…

とても勉強にはなりましたが、自力では何も出来なかったので落ち込みました。「まぁ何の知識も無い状態からスタートしてるしこういうもんだよね」という感じで切り替えて行くことにしました。ここまでで三日経ちました。

二つ目の課題(社内ツールのビューを作る)

二つ目の課題は「シナリオチームが使っている社内ツールがあって、変換部分は既に作ってあるから操作するためのビューを作ってください」というものでした。この辺りで私が想像していたサーバサイドエンジニアとは少し違った課題になりつつありますが、そういう仕事もやるんだという感じでやっていきました。

前回見たプロダクトのコードよりもかなり小規模で、Rails Tutorialをやったくらいの人間にはちょうどよかったです。また一から新しいものを作るというより、既存のコードを参考にしながら作れる部分がかなり多くてそれも良かったです。

またここで初めてRSpecというテストフレームワークを使ってテストを書きました。「ブラウザの操作をシミュレートして期待する動作をしているか?」みたいなこともヘッドレスブラウザを使って簡単に実装できるらしく、凄いと思いました。テストを書くのは大変だけど面白いと思いました。

この課題ではたまにメンターに助けてもらうこともありつつ(turbolinkのせいでCSSが当たらない、テストの文法が間違っていてブラウザの挙動がおかしいなど)、自分で調べたり考えたりしながら進められることも多く最終的にPRをレビューしてもらってOKを出してもらって、達成感がありましたし少し自信がついたので良かったです。自分のレベルに合った課題を割り振ってもらっているおかげですが。ここまでで五日経ちました。

三つ目の課題(社内ツールの機能修正)

次の課題は前回の社内ツールの機能に不具合があるのでそこを修正するというものでした。

この課題はそんなに難しい点は無かったので割とサクサク実装することが出来ました。先頭にBOMが付いている文字列と付いていない文字列を同値比較していてデバッグ出力してもぱっと見同じに見えるのになぜfalseが返ってくるんだ…?というところで若干ハマりそうになりましたが…

メンターには「ファイルを直接触るようなテストは環境に依存する可能性があるので、ファイルに書き出す文字列を返すような関数を作ってそれをテストする形にしたほうが良い」ということを教えてもらったりしました。

あとこの辺りからコミットメッセージを以下のgistを参考にしながら英語で書くように努めました。(あまり悩みすぎるところでは無いと思っていたので文法とか適当ですが…)
[転載] gitにおけるコミットログ/メッセージ例文集100 · GitHub

ここまでで七日経ちました。

四つ目の課題(社内ツールの入力フォームを作る)

四つ目の課題は手がけていた社内ツールの入力フォームを作って入力された値のバリデーションをしてごにょごにょやるというものでした。これがインターンの課題で一番大変でした。

とりあえず最初はモデルを作らずに入力フォームのビューを作ってバリデーションはそのままparamsに入っている値を直接見て有効な値で無かったらエラーメッセージを表示させて…みたいな方法でやろうとしていました。モデルを作らなくていいと思った理由は入力フォームの値をDBに保存したり読んだり、みたいな操作が必要無いのでモデルを作らないほうがいいのかな?と思ったからです。しかし実装している途中で「これいちいち空チェックのバリデーションを自分で実装するのは筋が悪い気がする…ActiveRecordを継承すればその辺楽になるのに…」と思って、DBにアクセスせずにモデルを作るってありなのかな?と思って調べてみると…ありました。

qiita.com

どうやら include ActiveModel::Model と書けばいい感じにバリデーションのメソッドを使えたりViewに紐付くように出来たりするようです。

というわけでモデルを作ってバリデーションはそれに任せる感じにしたらだいぶいい感じになりました。

次にやりたいのは「フォームの入力に失敗した時にフォームに入力した値を保持した状態でリダイレクトさせる」ことでした。これもなかなかいい実装が出来ず最初は失敗した時に入力フォームの値をセッションに一時的に保存してレンダーする時にその値を埋めてセッションに保持した値を消して…みたいなことをしていて「うーん」という感じでした。これもメンターに「いい書き方無いですかね…」と相談したところ、リダイレクト先にフォーム情報をクエリ文字列として渡すという方法でシンプルに解決することができました。

他にも色々メンターやWeb業界で働いていた人にもレビューをもらって様々な学びがありました(form objectの話とか)。また色々ハマったこともありました(form_withの挙動とか)。振り返ってみるとこの課題が一番苦労したなぁ…という感じです。その分達成感も一番あって自分でも頑張ったと思います。

ここまでで十一日経ちました。

五つ目の課題(社内ツールの機能追加)

インターンも終わりに近づいて残すところ後二日となりました。最後は手がけていたツールの機能追加…というか機能拡張ですかね。今まではViewを弄っていましたが今回はModelを作る感じでした。「後二日で終わるのかな…」という感じでしたが、ソースコードを読んでいると割と既存のコードを流用できる部分が多くてほとんどコピペして後は少し修正してテストを書くぐらいの作業で特にハマるポイントもあまり無く無事終わらせることができました。

開発以外にやったこと

以上がインターンでやった開発の内容です。インターンの仕事内容としては上記の開発がほとんどですが、それ以外にも色々なことを体験させてもらったのでずらっと書いていきます。

朝会(あさかい)

インターンは10:00出社なのですが、毎日10:05から朝会というものがありました。これはチーム全体で5分程度の時間を取って全体に共有したいことなどを伝える時間です。だいたいプランナーさんが売上状況とかゲームがどれくらい遊ばれているかとかイベントの状況などを共有することが多かったです。

昼会(ひるかい)

毎日14:30からは昼会というものがありました。朝会はチーム全体での共有でしたが、昼会は開発チームで集まって15分程度の時間を取って共有事項を伝えたり、「今まで自分が取り組んできたタスク・これから取り組んでいくタスク」を全員が一言二言で共有するという時間です。エンジニアは自分の開発にかかりきりになるとどうしても周りが見えづらくなってしまうことがあると思いますが、この時間があることでみんながどういうことをやっているのかを把握できるので良い取り組みだと思いました。

エンジニアミーティング

隔週火曜日17:00からはエンジニアミーティングがありました。これはチーム単位では無く社内全体でエンジニアが集まって外部から招いた人の話をしたり、インターン生の紹介をしたり、自分が作ったツールをみんなに紹介したり…という時間です。最初のエンジニアミーティングではセキュリティに強い人を招いたお話があってCTFの可視化の話があったり、バイナリかるたとかアセンブラ短歌という世界があるという話を聞いたりしてよく分からなかったですが「すげー」と思いました。

1on1

毎週火曜日は30分程度のメンターとの1on1がありました。業務中はなかなか落ち着いて話す時間も無いのでこういう時間を設けてゆっくり話をする、みたいな感じです。特に大層な話をしたわけでは無いですが、インターンのフィードバックを少しもらったりアカツキという会社について聞いたりその他は雑談をしていました。私は競プロをやっているのでその話をしていたら、この前マラソン系のコンテストで出た問題がメンターが10年くらい前の高専プロコンで取り組んだ問題と実はほぼ同じだった、という面白い話を聞けたのがよかったです。

インターンの成果報告

エンジニアのインターン生は私以外にも結構いました。インターン生は最終日に成果報告をすることになっているので、私も他のインターン生の発表を聞きに行っていたのですが、AWSの環境構築をガッツリやっている人やゲーム内のミニゲーム(正の得点を得ることすらめちゃくちゃ難しい)を作っている人の話を聞いて、みんな凄いレベル高い…と思って聞いていました。刺激を受けました。

ランチとか飲み会とか

たまにメンターが他の人を誘って一緒にランチに行ったり、インターン生が卒業するときに一回大々的に飲み会が行われたりしました。ランチでは他のプロジェクトチームの話を聞いたりすることができました。インターン卒業飲み会でアイマスにめっちゃ情熱を注いでいるインターン生がアイマスをめちゃくちゃ推してくれたのでちょっと見てみようと思いました。

インターンで感じたこと・学んだこと

ゲームはいろんな人が協力しあって出来ている

当たり前っちゃ当たり前ですが、実際みんなと同じフロアで働くことでより強くそれを感じることができました。エンジニアだけでは無く、プランナーさんが企画したりディレクションをしてくれたり、シナリオを作ってくれる人、絵を描いてくれる人、音を作ってくれる人、モーションを作ってくれる人、検証をしてくれる人……様々な人の協力で一つのゲームが作られていてそれって凄いことなんだ、と感じました。

アカツキの働く環境はめっちゃ良い

アカツキはオフィス環境作りにもかなりこだわりを持たれていて、そのおかげでみんながストレス無く働ける環境になっていると感じました。靴を脱いで素足で仕事ができるとか、各階におしゃれなカフェっぽい休憩スペースがあっていつでも自由に休めるとか、オフィスに緑があったりして心が安らぐとか(?)。オフィスにいるのが苦痛になってしまったら仕事も辛いものになってしまうと思いますが、オフィスがおしゃれで居心地が良いのでそういうことは全く無く非常に良かったです。ただトイレに行くときに靴を履かなきゃいけないのがちょっと面倒ですが…

またオフィスだけでは無く、一緒に働く人たちも皆それぞれ違った個性を持ちつつも良い人が多いんだろうという印象を受けました。今回のインターンでは他の人と一緒に仕事をするという感じでは無かったので、あくまで普段のオフィスの雰囲気を見て、という感じですが。話し合うことはたくさんあるだろうし、ときにはすれ違いなどもあると思いますが、ギスギスした感じでは無く笑いもありながら和やかな雰囲気で皆さん仕事に取り組んでいました。

終わりに

始めにインターンのお誘いをいただいたときは正直かなり悩んでいました。行った方が良いんだろうな…と思いつつ不安な部分も大きくて「行きます」と言った後も「やっぱり辞めとけば良かったかな…」と考えたりしていました。

それでも実際に来てみると、やっぱり大変なことやしんどいこともありましたが、それ以上に良い環境で働けて学ぶことや感じることも多くてトータルで見ると「来て良かった!」と思えるものでした。この度インターンでお世話になった人事の方やメンターの方、一緒に働いてくれた方々には本当に感謝しています。

それでは長くなりましたが、ここまで読んでくださってありがとうございました。

インターンで好き勝手働かせていただいた話

$
0
0
エンジニアインターンとして二週間アカツキで就業したstalagmiteさんの体験記をお届けします。「自分の理想とするエンジニア」を意識して働いたインターン、どのような経験をされたのでしょうか。その様子をレポートいただきます。

自己紹介

この度アカツキのもとで内定後インターンをさせていただきました。その時のことについて、主に自分が何を考えながら動いたかを書きたいと思います。 とても自分語りが多くなるかもしれませんが、多分アカツキの社風的に大丈夫だと踏みました。

所属当初の背景

大学では情報系の専攻をしていた。
大学での研究はOpenStreetMapのことについてやってる。
ゲーム製作サークルに所属していて、学祭でゲームの展示をしたりしていた。

プログラミング経験

C++,Haskell,C#,Unity,GLSL

隙間時間で調べてること

数学(圏論、集合論、確率論)
シェーダ
VR

普段やっていること

DxLibやOpenSiv3Dを触りつつゲームの部品を作ったりモックを考えたりしている
しかし完成したものはないという地獄

所属時の話と自分語り

大学でプログラムの勉強をしていると、プログラマーというのは「厳密に仕様を決めて高い水準で要求に答える」みたいな、専門家としてのSE像があった。 ただ、もともと大雑把な性格で緻密なことが苦手な自分は、「そういうイメージのプログラマになれるのか」という漠然とした不安があった。(もちろん、ある程度のコード力はあると自負はしているけれども、その専門家としての価値と自分の性格って合わないような気がしていた)
就職活動をしている中の、そんな漠然とした不安のを抱えているときに、アカツキとの面談や、会社の説明を聞く中で、

「うちで働いているエンジニアはそれぞれ違う部分で価値を出し働いている。」
「インフラのことについての専門性で貢献しているエンジニアもいれば、プランナーなどの別職と連携をとったり、自分で案を出しつつ実装までするエンジニアもいる」
「全員が自分で考えていて、受け身なだけの人はいない」

という社風に興味をひかれ、アカツキの入社を希望した。

インターンの目標

インターン初日、メンターの方に言われたのは、
「このインターンでの目標を決めましょう」 という抽象的なものだった。 働き方も、目指すものも、全部自分で決めて良い。
具体的な課題をひたすら潰すもよし、実際のプロダクトの小さい機能を設計から作ってもよし、「 インターンで僕が何か良いものが得られたと感じられる、それがこのインターンの意義です」と説明してくださった。
僕は、大手のゲーム業界でたまに、規模は大きいのにゲーム性そのものがイマイチなゲームというのがあるのが嫌だった。
これは入社前から持っていた偏見であるが、「イマイチになってしまうのは、プランナーが仕様を考えてエンジニアが実装して、それをプランナーに戻してまたフィードバックして、というサイクルが重いのが原因なんじゃないか」と思っていた。だから、僕はこのインターンの目標として
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニアになりたいです」
と答えた。
一つ重大な問題がある。僕は自分の「ゲームエンジニア」としての像をここに置いた。この作業はいわゆる「ヒアリングから問題点を聞き出し解決策に落とし込む」というまさにSEとしての分野であり、
僕は大学でこの内容の授業の単位を落としているのである。
ついでに言うともともと僕はコミュ障であって、就活中にも自己嫌悪で大変なことになっていたほどだ。もう不安しかない

最初の1週間

目標を決めた後、ソーシャルゲームの開発(クライアント)チームに配属された。このチームでは、プランナーエンジニア問わず、Trelloに

「何か改善すべき問題」
「さらにゲームを面白くするためのコンテンツ案」
「UIUXの改善案」

など、色々な抽象段階の案を共有することができることを教えてもらった。
ここから自分が面白そうな案、実現できそうな案を拾い、話を聞きに行く。
プランナーがしたいことを、現在実装がどうなっているかを把握できるエンジニアが聞き、仮設計を考え形にする
これは結構自分がやりたい立ち回りに近いものだと思えた。

ここで色々な意見を聞いていく中で、「ゲーム内のキャラクターの編成を組むときの、画面遷移を伴う操作が煩雑であり、それを改善したい」という意見をプランナーSさんに頂き、これは手を付ける影響も少なくて済みそうだし、いい感じに抽象的だったので、担当することにした。 幸い、個人的にプログラムのバイトの経験があったので、さほど時間を取られずに自力で規模の大きいコードを読みつつ、既存コード内のでのゲームデータの扱い方や簡単な画面遷移の処理を頭に入れ、最初の1週間のほとんどをヒアリングに使った。
ここで最初の山を迎えた。最初の実装、設計案を考えたときに、「これは難しい。既存の画面遷移の中にどうUIUXをいじっても、複雑な操作が発生してしまい、意味がなくなってしまう」という結論になってしまった。このことをプランナーSさんに相談しにいくと、
「もっと根本から考えてみたほうが良い。本当は、編成なんて1タップでできるんじゃないか?それが実現できたら、最も便利なんじゃないか?
僕は仕事として、与えられた役割としてプログラマを引き受ける時に、どうしても今確実にできることベースで物事を考えてしまう癖がある。それは情報系プログラマ、エンジニアとして大事な要素ではあるが、何かを解決したいときの思考方法ではない。なまじコードが読めるから、設計案が頭に浮かぶから、わかる範囲で片付けようとしてしまっていた。
なので僕は「1タップで自動編成」を一番上に置いて、それにもっとも近づくように、要求を分析することにした。これは、他のエンジニアに相談すると、「完全に自動編成するためには、キャラごとに編成する際の評価値を計算する必要があるが、その厳密な計算は難しい」
ということになってしまったのだが、
「他ユーザの編成を分析してそれを元に評価値を作れば、厳密な計算はいらないし、信頼性も高いのではないか」
という案が浮かび、既存の資産も活かせるということで、落とし所として、
「同レベル帯で成績の良い他ユーザの編成(=クリアログ)を自分の手持ちキャラなるべく似せて自動編成できる機能を作る」
とういことになった。(プランナーとエンジニアを行ったり来たりして解決案をだすというムーブ、これがしたかった)

これが決まった後、既存のコードを利用した設計と実装案、ドキュメントを書くことができた。
ここまで来るのに二度提案を練り直した。 この時点のドキュメントで
関数の影響範囲
この提案で操作が便利になるユーザー層の想定
までは書くことができた。ここまでは、いいペースだったと思う。

次の1週間

手をつけた課題についてドキュメントを書き、仮のコードも書いて、最初のプルリクエストを飛ばした。 当初の予想では、もっと議論が活発になると予想していた。というのも、僕が担当したのはロジックで、仮提案であり、現状のコードや設計により詳しい人にコメントがもらえるだろうと予測していた。ロジックだけでなく、本実装する際はUIUXの話も絡んでくるだろうと思っていたので、正直なところ「あれ、ウケが悪いな」と思った。
この時、元々の提案を出してくれたプランナーSさんが別の部署に行ってしまい、次にやることも含めて自分で考える必要が出てきて、3日ほど右往左往してしまった。

その後なんとか僕は、「現時点での提案の「自動編成の精度」が、どの程度良いのか分析できていないから、皆現在の提案の進捗が想像が難しいんだ」、と考えた。それは部分的には真で、自分でも「じゃあこの自動編成を使うと、どう便利になるの?具体的にどのユーザがどのように便利になるの?」という風に疑問に思っていた。なので次は、
「既存のユーザの分析」
「この提案で便利になるユーザとはどのような状況の人間か」
を調べることにした。

最後の1週間

mysqlをいじってアプリで使われているデータから、ユーザの手持ちキャラ、自動編成の通してみた結果を比較したデータを用意し、分析した。具体的には、自動編成後の編成のスコアの分布ごとに、
「編成結果のスコアがここのユーザたちは、ゲーム内ではこのコンテンツをするためにこの操作をすると考えられる」
編成結果の低いここのユーザ層は、そもそもここのコンテンツを触らないな。より良いコンテンツへの推奨はUIUXでこう解決できるな」
というところを分析し、ドキュメント化した。
また、このデータを他のエンジニアが検証できるよう、デバッグメニューの実装し、プルリクエストを飛ばした。 これによって、2回目のコメントもらい、時間的にも区切り的にもちょうど良いので本インターンでの作業を終了した。

総評

一応、ヒアリング、提案、実装、分析、デバッグメニューで他者に検証してもらうフロー、今後の展望のドキュメント、までを、いろんな人に話を聴きながら作り上げることができたので、最初の目標である、
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニアになりたいです」
という動きはできたのではないかと思う。
ただ反省点として、
「プランナーSさんがいなくなったタイミングで、この提案の実現の進路を考える人が自分以外にいなくなったことに気づかず、失速していた」 というのがあげられる。
本来これにすぐに気づき、次に決めるべき内容、この提案について本腰を入れて一緒に考えてくれる(自分以外の)人間を巻き込む必要があった。 (ずっとメンターにも相談していたのだが,いつも「次どうすればいいですかね」と聞いてしまった。僕が考えるべきだったことなのに)
確かに、僕はプルリクを飛ばしてエンジニアとしてコードを書いてドキュメントを書いて分析もできたが、じゃあこれが何かの役にたったのかというと、正直よくわからない。なぜなら
提案の進路、実現の持っていき方を考えていなかった

or
それを考えてくれる人間の確保が必要なことに気づかなかった
からだ。
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニア」
のそれっぽい動きはできたけれども、そういう立ち回りののオリジナルな価値を生み出せたかというと、それは少なかったように思う。
そもそも僕がやりたいこの動きって、「プランナー<->エンジニア間で速度の速いフィードバックをして、抽象から具体に落とし込む」というのをやりたかったのだ。 しかしそもそも、
「抽象的な目標、提案をチームの内側から通すって時は、具体的な設計、方針が決まるまでその提案の立ち位置、自分の立ち位置、他人の立ち位置をよく把握しなければならない」
、そうでなければ、空中分解しかねないという基本を、僕は知っておくべきだった。
これはものを考えるプランナーだけでなく、何かを作るという当事者全員が意識すべきことだったことに気づいた。
三週間のインターンなので、大きい規模を実現することはできないという前提があったなかで、最大限のことをしようと覚悟をしたはずなのに、その覚悟がまだ足りなかったように思う。
インターンが終わったらまた日常生活に戻る。そこには、大学でも、個人ゲーム制作チームでも、やり残していることがある。
来年アカツキに入社するまでに、それらにケリをつけて成長して出直そうと思った。

RubyKaigi 2019 に SAKE Sponsor として参加してきました!

$
0
0

こんにちは、18卒で入社したサーバサイドエンジニアの氏平です。
普段はゲームコンテンツの運用をしています。

アカツキが4/18(木)〜20(土)に福岡国際会議場で開催された、RubyKaigi2019 に SAKE Sponsor(Platinum)として参加してみてきましたのでレポートをしたいと思います!

はじめに

アカツキでは Ruby on Rails を使用して、ゲームのサーバーサイド(APIサーバ・管理画面・インフラ)の開発・運用を行っています。普段業務で使用している言語の最新の情報をキャッチアップしてこようと今回 RubyKaigi 2019 に参加しました。
アカツキからは8名の参加です。

RubyKaigi とは

Ruby の中で最大級の国際会議。 

rubykaigi.org

世界中からコミッターや開発者が集まり、Ruby の新機能の情報や開発事例などが紹介されます。
RubyKaigi 2019 では主に 現在開発中の Ruby 2.7 と Ruby 3.0 の機能紹介が行われました。

f:id:sejimhp0808:20190425220455j:plain

 

アカツキブース出展

今年はアカツキとしてスポンサーブースも出展したので紹介させていただきます!

アカツキから配信している「八月のシンデレラナイン」(通称ハチナイ)をベースにブースを出展しました。
野球盤を用意し*1ヒットを打てた方にオリジナルカレーをお渡しするというゲーム形式です。 

ハチナイのアニメもちょうど4月から始まり、見てくれた方もいたので楽しくコミュニケーションを取ることができました。

f:id:yusi:20190426170649p:plain

 

Matz さんもブースに来てくださって、オリジナルカレーを持って帰っていただきました!

f:id:sejimhp0808:20190425220816p:plain

 

SAKE Sponsor として参加して

RubyKaigi の後、毎夜パーティーが開かれました。
その中で RubyKaigi 2019 Official Party で我々がスポンサリングしたお酒が配られました!

f:id:sejimhp0808:20190425220514j:plain

中洲川端商店街を貸し切りのイベントでお酒以外にも地元の名物も多数配られました。
美味しいご飯を頂きながら、いろんな方とお話することができました!

f:id:yusi:20190426170926p:plain

KBC九州朝日放送のニュースにも取り上げられたようです!
地元の方にも喜んでいただけてよかったです!

kbc.co.jp

 

さいごに

目黒周辺では Meguro.rb という Ruby の Meetup が定期的に開催されています。
5月開催はアカツキではないですが、LT大会や懇親会などございますのでぜひお越しください!

megurorb.connpass.com

 

f:id:yusi:20190426171125p:plain

*1:エポック社さんの許可をいただき、野球盤をアレンジしました。

【LT会】Akatsuki Geek Live開催レポート!Vol.2

$
0
0

こんにちは、エンジニア採用担当の花田です。

元号を跨ぐ大型GWも終えましたが、去る4/26(金)に学生向けLT会「Akatsuki Geek Live Vol.2」を開催いたしました!

2月の初開催に次ぐ、2度目の開催となりましたが、今回もリピーターを含む約30名の学生の方に集まっていただき、序盤から大いに盛り上がりました!この記事では、その様子を紹介いたします。

 「Akatsuki Geek Live」とは...

学生エンジニアと、アカツキエンジニアが登壇するLT会です。今回は学生3名、アカツキメンバー5名の計8名が発表しました。その後、参加メンバーで懇親会を実施、学生同士やアカツキメンバーとの交流をいたしました。

▼イベント概要はこちらから

aktsk.connpass.com

▼なぜLT会を開催するに至ったのか

初回の開催レポートに開催の思いを綴っていますのでご興味ある方は、こちらから

hackerslab.aktsk.jp

 #当日の様子

前回、前半のLT会はかなり真面目な雰囲気で進んでいき、後半の懇親会では、わいわいと盛り上がりました。それはそれで良かったのですが、今回は序盤から更に盛り上げていきたいと思い、LT会スタート時から参加者の方にドリンクを取っていただきました。カジュアルな空気で開始したこともあり、Twitterも序盤から活発に動く中、早速スタートです。

 

▼1人目:@3nan3さん(アカツキ)

「Ruby/Railsで、key-valueなオブジェクトから値を取得するイディオム」

1人目は、アカツキメンバーから!Ruby on Railsで「おれはHashから値を取り出したいだけなんだ!」という熱い思いを語ってくれました。

f:id:kenji-hanada:20190509203211j:plain

発表資料

qiita.com

 

▼2人目:@カレーエンジニアkomaiさん(アカツキ)

「世界最大級のゲームカンファレンスGDCって何?どんな雰囲気なの?どうやったら行けるの?」

2人目もアカツキから、絶品カレーを振舞うエンジニアが3月にサンフランシスコで開催されたGDC 2019の紹介をしてくれました!

f:id:kenji-hanada:20190509203208j:plain

発表資料

speakerdeck.com

 

▼3人目:@諏訪さん(アカツキ)

「What's "Google Cloud Next"?」

3人目もアカツキから諏訪さん。GDCに続いて、4月にサンフランシスコで開催されたカンファレンスの参加レポートを紹介!

f:id:kenji-hanada:20190509203205j:plain

発表資料

speakerdeck.com

 

▼4人目:@きょーまさん(アカツキ)

「C#のリフレクションを使ってみよう」

4人目はアカツキ枠からきょーまさん!C#のリフレクションについて基本的な使い方と便利な使用方法を紹介してくれました。

f:id:kenji-hanada:20190509203202j:plain

発表資料

speakerdeck.com

 

▼5人目:@yasu0327さん(学生)

「ゼロから始めるGo Modules」

5人目は学生枠からyasu0327さん。Go Modulesの管理機能とその流れを紹介してくれました!最近Goに取り組まれている学生さん多いですね!

f:id:kenji-hanada:20190509203157j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

 

▼6人目:@給前さん(アカツキ)

「Unityエンジニアを目指す方が、学生のうちに学んでおいてほしい技術」

6人目はアカツキから、Unityエンジニアを目指す方向けに、自身の学生時代の学習方法・内容を交えながら語ってくれました。勉強量がとにかくすごい。

f:id:kenji-hanada:20190509203151j:plain

 

▼7人目:@Matts966さん(学生)

「Go言語で書くLispインタプリタ」

7人目は学生枠からMatts966さん!この発表では特に「タイトルがもう強い」「Lispインタプリタすごい」とTweetが盛り上がっていました!

f:id:kenji-hanada:20190509203148j:plain

発表資料

 

▼8人目:@takanakahikoさん(学生)

「学生がOSSに挑戦するということ」

トリを務めるのは学生枠よりtakanakahikoさん!OSSへの挑戦について語ってくれました。実は私も彼が作った拡張機能を使わせて頂いています!

f:id:kenji-hanada:20190509203140j:plain

発表資料

speakerdeck.com

 

8名による熱のこもったの発表はあっという間にすぎ、懇親会へと移ります。

今回も学生 x アカツキメンバーの交流が盛んで、至るところで笑い声が聞こえました。中にはセグウェイに乗りながら懇親会に参加するメンバーも笑

f:id:kenji-hanada:20190509203137j:plain


参加者のみなさん、お疲れ様でした!

今回、アカツキの技術領域の話はもちろん、海外カンファレンスの話や、学生同士の交流を通して、これからの一歩を踏み出す一つのきっかけとなったのではないでしょうか。

次回は7/1(月)に開催予定です!またエネルギー溢れる皆さんにお会いできることを楽しみにしています^^

f:id:kenji-hanada:20190509203134j:plain

 ▼次回予約はこちらから

aktsk.connpass.com

インターンでミニゲームづくりに挑戦しました。

$
0
0

エンジニアインターンとして2週間アカツキで就業したkeiwさんの体験記をお届けします。ゲーム開発は経験があったものの、これまで触れてこなかったUnityでの開発。課題としてミニゲームづくりに挑戦してもらいましたが、どのような学びがあったのでしょうか。今回はその様子をご紹介します。

 

こんにちは、2週間ほどインターン生としてお邪魔させていただきましたkeiwです。

 

今回、2週間で、ちょうど企画フェーズにあったバッテイングセンターのミニゲームをインターンテーマとして挑戦させて頂きました。今後、ハチナイ開発チームによる改修などを経て実際ゲームに登場するかも、とのことですが、自分が作ったものの何割が残れるか楽しみです。

この記事では、そのインターン体験記的なことを書こうと思います。(拙い文章ですが、お付き合いください^^;)

 

以下、目次です。

 

 

インターン開始まで

インターン開始まであと1ヶ月のとき。UnityとC#、GitHubをさわってくるように言われました。ゲーム作りはそれまで、バンバンやってきたのですが、それらはノータッチ。やってきてねと言われたリストは一応一通り試したのですが、他の用事などもあって十分にはさわれず、不安しかありませんでした。

 

インターン開始!

不安(と期待もあった)を胸に始まった初めてのインターンでしたが、自分が配属されたチームは会社っぽいというよりは雰囲気は高校の部活という感じで、技術的な不安以外はだいぶ緩和されました。ほとんどの読者には伝わらないと思いますが、とくにアイスブレイク担当を指名する愉快な茶番は面白かったし、そのアイスブレイクの内容自体もけっこう面白かったです。スターウォーズ昼食会などもよかったです。

 

壁、壁、壁!

初めての事ばかりで、当然壁にもぶち当たりました。

まずは、技術的な問題。雰囲気はよかったものの、やはり技術的な不安は的中してしまいました。1か月前からある程度さわってきたとはいえ、ほとんど初心者のUnityやGitHub。けっこう苦戦しました。何よりもMacPCには準備期間もなく、最後まで慣れなかったですね。(普段使っているWindowsやUbuntuもデキるわけではないのですが^^;)

また、今まで個人で何本かゲームを作ってはいたのですが、企画もイラストもコードも全て一人でやってきて、ゲームの内部的なところを人にみてもらうのは初めて。特にプログラムは1か月後の自分が再び編集し始められる程度を目安に書いていたので、人に読んでもらうことを前提とした書き方はなかなか難しかったし、恥ずかしかったです。ただ、細かく丁寧にコメントをしてもらえ、恥ずかしさによる抵抗感はすぐに消えました。

 

成果報告(一応メイン)

先ほど述べた通り2週間でミニゲームをつくることになりました。
ボールが飛んでくる。タイミングよく打つ。飛距離がスコアになる。というバッティングセンターを模したシンプルなゲームをつくりました。以下にゲームの使用を簡単に説明し、できたゲームのスクショにコメントを添える形で成果報告とさせてもらいます。

簡単な仕様

初めて見た現場の仕様書。ちょっと感動しました。

かなり簡単に書くと、

 1:画面内にいるバッターのストライクゾーンめがけてボールが飛んでくる
 2:それを画面をスワイプすることで打ち返す
 3:スワイプのタイミングと位置に応じて飛距離(スコア)が決まる

というもの。これを10球1セットで遊びます。イメージ図もあり、非常にわかりやすく、また作る前からワクワクしてました。

簡単なフロー

下図のように状態遷移させることで実現させました。

f:id:aktsk_keiw:20190315141602p:plain

・「初期化1」

 10球ごとに初期化が必要なものの初期化

・「初期化2」

 1球ごとの初期化

・「準備OK?」

 ボールがいきなり投げられるのを防止。タップで「メイン」へ

・「メイン」

 高スコア目指してバッティング!
 スコア計算はスワイプ終了直後にされる

・「ヒット」

 バッティング成功したら、キャラのカットインが入り、
 スコアがカウントアップするシーンが入る

・「空振り」

 バッティング失敗。タップで「初期化2」に戻り、もう一度トライ!

・「結果」

 今回のスコアを表示。

・「最終結果」

 今回で最高スコアと今までの最高スコアを表示。

プレイ画面

f:id:aktsk_keiw:20190315143155p:plain

「メイン」の画面です。主に右下の赤い十字めがけてボールが飛んできますが、ボールは少しブレます。ボール到達直前に青い十字が出るので、出来るだけ近い位置で指を離そう!

f:id:aktsk_keiw:20190315143834p:plain

「ヒット」のカットインです。バッティングに成功すると見れます。さらにスコアによって効果音が変わります。

f:id:aktsk_keiw:20190315144038p:plain

「最終結果」です。記録更新を目指せ!

スコア計算

スコア計算に使う主な要素は3つで、その要素を掛け合わせることでスコアを決定しました。

・スワイプで指を離すタイミング

・スワイプで指を離す位置

・スワイプにかける時間

工夫・苦労した点

工夫・苦労した点はやはりスワイプの判定です。きちんとスワイプしたかどうかの判断は4つのチェックポイントを設け、順に通過させた場合のみ、きちんとバッティングしたと判断するようにしました。通過したチェックポイントは色を濃くするようにし、次回へのフィードバックができるように工夫してあります。

他にも指を離した位置に白い十字マーカーを置くことでも、失敗しても「次こそは」と思えるようにしてあります。

また、タイミングの判定が悪ければ、面白くならないどころか、理不尽さにイライラしてしまうだけので、タイミングの判定にも工夫をしました。スワイプを終了すべき正しいタイミングを把握するために、発射されたボールの位置を把握してストライクゾーンをいつ通過したのかを把握するのではなく、ボールがストライクゾーンに到達するまでの時間を変数でおき、その変数に応じてボールを動かす感じ(変数が0の時がストライクゾーン通過中)で、正確なスワイプを終了すべきタイミングを得ました。

 

成果報告は以上です。

慣れないツールで、2週間は短かった。やり足りない部分もありますが、自分自身ワクワクしながらでき、先日の簡単なお披露目会では楽しそうにやってもらえたので、おおよそ満足。

 

反省・その他

初めての場所で初めての事ばかりで緊張しまくりの状態。集中したらちょっと周りが見えなくなる性格もあいまって、雑談とかはあまりできなかった。ちょっともったいなかったなぁ。


今後、同じようなインターンを受ける場合、ただ絵を画面に表示させるだけなどの何もしない状態でも実機で試すまでの一連の流れを3日目くらいまでにやるべきだったかなぁと。

色々とギリギリだった今回のインターン、デザイナーさんに絵素材をお願いする機会もあったのですが、背景絵を翌日にもらえないかと無茶な依頼もしました。でも、翌日にはハイクオリティの絵素材が! 感謝するとともになんか感動してしまいました。

 

最後に

サポートしてくれたメンターさんをはじめとする野球チームの皆さんや、人事・総務の皆さん、非常に濃密な2週間をありがとうございました。

初めてのインターンがここでよかったです!


インターンでCloud Runに挑戦した話

$
0
0

エンジニアインターンとして約1ヶ月アカツキで就業したyasuさんの体験記をお届けします。来年4月に入社予定のyasuさんですが、今回の経験で入社までの課題も見えてきた様です。

はじめまして、yasuといいます。
今回私はアカツキで内定者インターンに参加させて頂きました。
期間は1ヶ月ほどでしたが、色々と貴重な経験をさせて頂けたので具体的にどのようなことをしたのか紹介して行きたいと思います。

自己紹介

私は現在、大学で経営工学を学んでいる4年生です。
普段は趣味でGo言語を主に触っています。
Go言語で主にやっている事としては研究室のSlackボット開発や自分用のブログエンジンの開発、ハッカソンなどでネイティブアプリ用のAPIの開発などです。
最近はOSのカーネルやコンパイラなどソフトウェアの中でも低いレイヤーに位置する技術に興味があります。
新しいものが好きです。

きっかけ

きっかけは逆求人イベントでした。
逆求人に参加した際に会社訪問に誘われ、そのまま選考 =>内定 =>インターン参加という流れです。
大学3年生のころに一度インターンに参加したことがあり、アカツキの技術に対する挑戦的な姿勢や「なぜ?」を大切にする社風、オフィスの快適さに惹かれてすぐに内定承諾とインターンに参加することを決めました。

何をしたのか?

今回は面接の際にお世話になった坂尾さんの所属するゲームの基盤開発チームでお世話になり以下の3つのタスクをこなしました。

  • 基盤の管理システムのCloud Run移行
  • 基盤の管理システムの操作ログのBigQueryからStackdriver Loggingへの移行
  • アプリケーション側でのIP制限機能の追加

今回利用したCloud Runについて

公式の説明ではRun stateless HTTP containers on a fully managed environment or in your own GKE cluster.と書かれています。
Google Cloud Next ’19で発表されました。
Knativeをベースにしたサービスで、オートスケールの機能やインフラ周りの設定の自動化などが特徴です。
Cloud Run ではContainer Imageさえあれば、その他の設定はほとんど自分でせずにデプロイできます。
公式ではCloud Buildを使ってContainer Imageをビルドしているので今回はCloud Buildも合わせて利用します。

基盤の管理システムのCloud Run移行

今回のインターンの大本のタスクです。
もともとGAE FEで動いていた基盤の管理システムをCloud Runへ移行します。
このタスクをこなすために次のフローを踏みました。

  1. アプリケーションのCloud Runでの動作確認
  2. Cloud Run へCircleCIでデプロイするようにする

アプリケーションのCloud Runでの動作確認

もともとGAE FEを使用していたので既にアプリケーションを動かすためのDockerfileが存在しました。
これをドキュメント通りにCloud Buildでimageをビルドしてgcloud beta run deployをするとすんなりとデプロイ出来ました。

また、GAE FE上でシステムを動かしていた際にはこちらのイメージを使っていたのですが、余計なパッケージを含まないようにDockerオフィシャルのPythonイメージを使うようにDockerfileを修正しました。

Cloud Run へCircleCIでデプロイするようにする

管理システムはCircleCIを使ってデプロイを自動化していたのでCircleCIのconfigファイルを修正する必要がありました。
具体的にはGAE FE向けに書かれていたconfigファイルをCloud Buildを使ってイメージをビルドし、Cloud Run へデプロイするように書き直す必要がありました。
gcloud build submitコマンドでイメージをビルドし、gcloud beta run deployコマンドを使ってCloud Run へデプロイするよう修正しました。

システム操作ログのStackdriver Loggingへの移行

管理システムの監査のための操作ログを、もともとは BigQuery に書き込んでいました。 これを Stackdriver Logging へ移行しました。
このタスクでは次の事を行いました。

  1. Cloud Run 上でStackdriver Logging の構造化ロギングが動くことの確認
  2. ログのデータ構造を定義する
  3. 構造化ログを吐くように操作ログのコードを修正する
  4. ログをRequestログと紐づけて表示できるようにする

Cloud Run 上でStackdriver Logging の構造化ロギングが動くことの確認

Cloud Run では 標準出力・標準エラー出力などにログを書き込むことで、 Stackdriver Logging に自動で集約されます。 またJSON文字列でログを書き込むことで Stackdriver Logging の LogEntry に jsonPayload として格納されます。
これを構造化ログと呼びます。
今回はこちらを使用して操作ログを記録することにしました。
参考 Using simple text vs structured JSON

print('{"sample": "hello"}')

実際に上記のようなJSON文字列でログを標準出力に吐くとLogEntryのjsonPayloadに入り、無事に構造化ロギングが動くことを確認できました。

ログのデータ構造を定義する

操作の際に送信されるパラメーターと送信元と送信者を特定するメタデータをログの構造としてまず定義します。 今回は操作ログなので操作内容と実際に操作しているユーザーのemailなどのメタデータをログのスキーマとして定義しました。

構造化ログを吐くように操作ログのコードを修正する

その定義していた構造通りにJSON文字列をログとして出力します。
今回はFlaskのapp.logger(python標準のloggingライブラリ)を使って標準エラー出力へJSON文字列を吐き出すようにしました。

ログをRequestログと紐づけて表示できるようにする。

Requestログとの紐づけは次の資料を参考にしました。

https://cloud.google.com/run/docs/logging#correlate-logs

In the Stackdriver logs viewer, logs correlated by the same trace are viewable in "parent-child" format: when you click on the triangle icon at the left of the request log, the container logs related to that request show up nested under the request log.

Container logs are not automatically correlated to request logs unless you use a Stackdriver Logging client library. If you want this correlation without using a client library, use a structured JSON log line that contains a trace field with the content of the incoming X-Cloud-Trace-Context header. Then your logs will be correctly correlated to the request log.

https://cloud.google.com/logging/docs/agent/configuration#special-fields

logging.googleapis.com/trace is stripped from jsonPayload and assigned to the LogEntry trace field. For example, assume the value of logging.googleapis.com/trace is [V]. [V] should be formatted as projects/[PROJECT-ID]/traces/[TRACE-ID], so it can be used by the Logs Viewer and the Trace Viewer to group log entries and display them in line with traces. If autoformat_stackdriver_trace is true and [V] matches the format of ResourceTrace traceId, the LogEntry trace field will have the value projects/[PROJECT-ID]/traces/[V].

飛んでくるRequestからHTTP HeaderにあるX-Cloud-Trace-Contextの値を取ってログとして吐くだけです。

ちなみにX-Cloud-Trace-Context
X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE
というフォーマットになっているので
/以下を取り除いてTRACE_IDだけ抽出する必要があります。
このTRACE_IDをログとして吐くJSONのlogging.googleapis.com/traceキーのバリューとして設定します。
そうするとLoggingエージェントが収集し、LogEntryのtraceフィールドに自動的にTRACE_IDを設定してくれます。
これでStackdriver Loggingでリクエストログと紐付き、まとまったログとして見る事ができます。

アプリケーションへのIP制限機能の追加

今回の基盤の管理システムは社内用ツールであるため社外からアクセス出来ないようにする必要がありました。
GAE FEではGAEのfirewallの機能でIP制限をしていたのですがCloud Runでは現時点でそのような機能が提供されていませんでした。
なので、今回はアプリケーションレイヤーでIP制限機能を実装することにしました。

最初は Flask の request.remote_addr の使用を試みてみたのですが、 Cloud Run にデプロイすると、これには Google Frontend の IP アドレスが設定されるということがわかりました。
X-Forwarded-For には Google Frontend がクライアントの IP アドレスを付与してくれていたため、こちらの IP アドレスを使用してアクセス制限機能を実装しました。

Cloud Run を実際に使ってみて

学習コストが低いので初学者でもすぐに始められて良いと感じました。
インフラ周り初心者の私でもすんなりデプロイできたのでの学習コストはかなり低いなと感じました。
また、デプロイをすれば設定など何もすることなくスケーリングなどのサーバー全般の管理をGoogleがやってくれるのでかなり便利だと感じました。

インターンで学んだこと

何をするにも なぜ? そうしたのか深堀ること。

インターン中一番改善しなきゃいけないと思った点はこれです。 どのタスクの際にも技術を理解せずに突き詰められていた事が多かったと思います。 例えばシェルスクリプトでShebangを使っているのにshコマンドを使っていたことがありました。

また、traceの設定の仕方もドキュメントを読めばしっかり書いてあるのに網羅的に読まなかったせいで見落としていたりしていました。 プルリクエストで詰めて頂いたおかげでかなり勉強になったので凄く感謝しています。 理解しないで実装するのは結局はバグや脆弱性を生み出し非効率なので一番自分が成長しなければならない部分だと感じました。

チーム開発でのコミュニケーションの大切さ

普段私はハッカソンや個人開発を主にしていたこともあり一人よがりな開発をしがちです。 そのせいで今回、妙に一人で抱え込んだりして余計に時間をかけたり心配をかけてしまったりしていました。 開発の効率にも関わる問題なので普段からのコミュニケーションも大切にしていきたいなと感じました。

良かったこと

新しい技術に挑戦できた!

他社でのインターンやバイトは自分のできる技術をベースにできることを任されることが多かったです。 しかし今回のインターンではCloud Runという発表されて間もない新しい技術を触らせて頂いた上にインフラ部分の移行を任されるという大きな課題に挑戦できたので他では体験出来ない有意義な経験が出来ました。 プルリクエストのコメントも議論が活発でそこから学べる事も沢山あったので凄く感謝しています。 今までのインターン経験上一番悩んで、一番楽しかった1ヶ月でした。

働きやすい環境が用意されている!

アカツキさんのオフィスではみんなが楽しんで仕事をしている雰囲気があり、オフィスも働きやすい設備(バリスタが常駐してたりとか休憩スペースが用意されてたりとか...etc)が整っていたので非常に働きやすかったです! 私の経験上一番働きやすい環境だと思いました。

最後に

2年前にアカツキでインターンをした際も感じたのですが、アカツキの働きやすさを改めて実感できた1ヶ月だったと思います。 インターン生が行うタスクに関しても他では経験できない裁量が与えられる非常に有意義なものでした。 また、今回のインターンで入社するまでのあと半年で解決すべき私自身の課題も見えてきたので半年後には進化した姿でまた戻ってこれるように精進したいです。 今回色々と見て頂いた坂尾さん、田中さん本当に感謝しています。

長々と書いてしまいましたが最後までお付き合い頂きありがとうございました!

【LT会】Akatsuki Geek Live開催レポート!Vol.3

$
0
0

こんにちは、エンジニア採用担当の宮田です。

先日7/1(月)に学生向けLT会「Akatsuki Geek Live Vol.3」を開催いたしました!

2月・4月に次ぐ3度目の今回は、梅雨になり、ジメジメした天気が続く中、パッとしないお天気をカラッと晴らしてしまうぐらい、パワフルで大盛り上がりの会になりました!この記事ではそのイベントの様子をご紹介いたします。

 「Akatsuki Geek Live」とは...

学生エンジニアと、アカツキエンジニアが登壇するLT会です。今回は学生5名、アカツキメンバー5名の計10名が発表しました。その後、参加者全員で懇親会を実施し、交流の場を持ちました。

▼イベント概要はこちらから

aktsk.connpass.com

 ▼なぜLT会を開催しているのか

初回のレポートに開催の思いを綴っています。ご興味ある方はこちらもご覧ください

hackerslab.aktsk.jp

#当日の様子

序盤からTwitter上で知り合いだったけど顔を合わせたことがなかった人、学校が一緒でこのLT会でお互いの参加を知った人たちなど、思いがけない出会いが判明する中、今回もドリンクを片手にカジュアルな雰囲気で早速スタートです。

 

▼1人目:@きたばやしあでぃ(@tk_adio)さん(アカツキ)

「“はやく“開発するための開発速度のあげかた」

 トップバッターはアカツキから!スクラムマスターでもある金髪のあでぃが“はやく“開発するためのポイントを紹介してくれました。チーム開発のあるある話にみなさん頷いて聞き入っていました。

f:id:kayomiyata:20190704183714j:plain

 発表資料

www.slideshare.net

 

▼2人目:@梶原さん(アカツキ)

「Elixir におけるリスト反転処理の実装を覗いてみよう」

続いてもアカツキから。サーバサイドエンジニアの梶原さんが、アカツキでは初めてプロジェクトで使用に至ったElixirについて、紹介をしてくれました。

f:id:kayomiyata:20190704185429j:plain

 発表資料

speakerdeck.com

 

▼3人目:@大嶋さん(アカツキ)

「カジュアルゲームとチュートリアル 〜実はチュートリアルが一番複雑になってませんか? ちょっとの工夫で改善!〜」

続いてアカツキ大嶋さんによるピッチです。

来たる夏、ハッカソンやイベントでゲーム作りをする機会が増える時期だからこそ心がけたいポイントを伝授してくれました! 

f:id:kayomiyata:20190704192215j:plain

 発表資料(slideshareには代理で登録しています)

www.slideshare.net

 

 ▼4人目:@konnyaku256さん(学生)

「Hyperdashで機械学習モニタリングをやってみよう」

 満を持して、学生さんの登場です!konnyaku256さんが、デモも交えて機械学習におけるあるあるな問題をモニタリングで解決する方法について語ってくれました。

f:id:kayomiyata:20190704192904j:plain

登壇資料 

speakerdeck.com

 

▼5人目:@細川さん(アカツキ)

「CloudFormationと付き合い続けよう」

アカツキ新卒2年目の細川さんは、将来大規模システムに携わる際に役に立つ内容を実体験をもとに発表してくれました。

f:id:kayomiyata:20190705142620j:plain

 登壇資料

www.slideshare.net

 

▼6人目:@f4snさん(学生)

「オンラインゲーム救命救急」

学生枠2人目のF4snさんは、初めてのピッチとは思えないぐらい落ち着いて話をしてくれました!

f:id:kayomiyata:20190704194002j:plain

登壇資料

speakerdeck.com

 

▼7人目:@河野さん(アカツキ)

 「大規模Railsアプリケーションをバージョンアップするときのハマりどころ」

サーバサイドエンジニアの河野さんは、大規模プロジェクトに所属しているからこその苦労話をしてくれました。

f:id:kayomiyata:20190704194845j:plain

登壇資料(slideshareへは代理で登録しています) 

www.slideshare.net

 

▼8人目:@ぷらすさん(学生)

「5分で分かるClean Architecture」

ぷらすさんは、オススメ本やビジュアルも用いながらClean Architectureについてわかりやすく説明してくれました! 

f:id:kayomiyata:20190704195419j:plain

登壇資料

speakerdeck.com

 

▼9人目:@がっちょさん(学生)

「世界を創造するOSS開発を始めた話」

がっちょさんは、ご自身で開発したOSSライブラリについて、開発情報含め紹介してくれました!

f:id:kayomiyata:20190704195842j:plain

登壇資料

www.slideshare.net

 

▼10人目:@Dopponさん(学生)

「Slackをハックしよう」

ここで飛び入りでのピッチをやってくれる学生さんが!

トリを飾るのはDopponさんによる、Slackをハックしよう!という話です。

f:id:kayomiyata:20190704201946j:plain

登壇資料

speakerdeck.com

 

総勢10名による熱のこもったピッチはあっという間に過ぎ、懇親会へと移行します。

LT発表内容についての質問や、最近興味を持っている技術についてなど、話題に花が咲いていました。中には自分で作ったゲームを見せてくれる学生さんも。

f:id:kayomiyata:20190705210500j:plain

登壇者のみなさん、そして参加してくださったみなさん、本当にお疲れ様でした!

アカツキメンバーや学生同士の交流を通して、この時間がこの夏また一歩踏み出すきっかけとなっていたらとても嬉しいです。

夏を経てさらに成長した姿のみなさん、また新たに興味を持ってくださる学生さんと出会えることをいまから楽しみにしています!次回また会いましょう^^

f:id:kayomiyata:20190705213001j:plain

 

▼次回の開催は2019年秋頃予定!

 

Akatsuki Summer Internship 2019-7

$
0
0

はじめまして、イチノセです。

この度、株式会社アカツキにて「八月のシンデレラナイン」の部署にて3週間就業型インターンをさせていただきました。ここで何を学び、何を見たのか語っていきます。

 

経緯

2018年12月、私はインターンを探していました。将来の就職のために行くに越したことはないと思いネットで探していました。探している中、普段からお世話になっている教員の方から「アカツキで新しいイベントをやるから行ってみては?」と勧められ、そちらの会社ではお世話になった先輩が就職した会社であるということもあり、アカツキのイベントに参加することにしました。

 

「Akatsuki Geek Live」と呼ばれるそのイベントは、LT(Lightning Talks)と呼ばれるプレゼンテーションを企業と学生から数名ずつ募り登壇するイベント(以下LT会)でした。第1回目は2月にあり私は聴衆側でしたが、エンジニアの集う会ということもあり、面白い話を多く聞きました。何度かLT会にお邪魔させていただいてると夏に3週間就業型インターンシップがあると聞きました。

 

こちらでは参加期日が3種あり、7〜9月の頭の平日からそれぞれ3週間ありました。3週間という長いインターンであり、参加したら他の会社のインターンを受けることができないと思った私は学校と話をつけて7月の頭から3週間インターンに参加することにしました。

 

目標

こちらのインターンでは何をテーマにするかを初めに自分で決めるところからスタートします。テーマを決めたらメンターの方と話し合ってテーマに対する目標、そのための道筋を一緒に考えました。

選べる道が多い中で「データ管理、効率化をより深掘りしていく」ことを目標にしました。私はワークフローエンジニア(データの管理、効率化を図るエンジニア。エディタやパラメータ管理、処理軽減など)を目指しており今までの制作の中ではそちらの処理に関わる機会が多くありました。今回のインターンではそちらの実力を伸ばそうと考えたのです。

 

インターン課題1

目標を決めた後はタスク管理ツールを閲覧して、どのタスクが目標に沿っているか確認して課題を決めていきました。候補はいくつか挙げられた中で、デザイナーからのタスクに「デバッグ機能としてキャラクタのシーン画像を追加した際の表示範囲、座標をどのスマートフォン検証端末からでも確認できるようにしてほしい」とありました。データの管理に沿うということで今回はこちらの作業を行うことにしました。

初めはすぐに作業を開始するのではなく会社のコードを読むところから始まりました。会社の方で参考になる処理があれば使用できるからです。コードを読んで3日ほどで作業に取り掛かり始めました。コードを読んだりメンターの方と話して知ったのですが、IOSに合わせて画像サイズを合わせた後、画像の表示可能範囲、必須表示範囲からIOSに合わせた表示範囲を計算して描画してくれるオブジェクトがすでにあるそうなのでそちらを利用しながら作業しました。

そちらを加えた後は画像の情報を取得する手段について考えました。画像の表示位置を変更したい、表示範囲を変更したい、画像自身を移動させたいなど後々で変更もできるようにしようと思い、画像の表示範囲、座標をUIで表示し変更ができるようにしてデザイナー側からも楽に変更ができるようにしました。さらに画像自身をスライドして表示中心座標を感覚で変更できるようにしました。

こちらのゲームではキャラクタの画像を閲覧する方法として、パラメータ確認の時にも閲覧できるようになっています。そちらの挙動も確認できるようにしたほうがいいということを話し合って挙動を追加しました。そしてこれらUIの表示を消すフルスクリーン機能、読み込みの処理の多重化など測りました。

 今回の制作では、使いやすくわかりやすい機能を目指して開発できたのでいい経験になりました。

 

インターン課題2

次の課題は「対戦時のキャラクタ表示を上記で使用したオブジェクトを使用して表示する」ことすることでした。表示方法が「背景、半透明の黒、キャラクタ」の順で後ろから表示します。こちらではSSR未満の場合には背景はデフォルトの背景画像、SSR以上ならばキャラクタの背景画像を表示させていました。しかし、私がオブジェクトを追加してこの処理を真似て表示させようとすると背景と画像で表示範囲が合いませんでした。そちらの原因を調べていると背景とキャラクタの継承先が違く描画手段が違っていました。ならばと、背景抜きをするシェーダーを背景を薄暗くするシェーダーに書き換えて完成させようとしたのですがその途中で作業は中断してしまいました。なぜならば、今回のインターンの期日が来てしまったからです。

今回のインターンで一番悔やむことと言えば最後まで作業をやり抜けなかったことです。余裕を持って全ての作業を完成できなかったことが大変残念です。

 

総評

上記で書かなかったこと以外では、「Git」「アセットバンドル」について関われたこと、チーム制作を学校で行っていた身として会社の制作は経験として得られたこともデータ管理関係として深く理解が得られたと思います。課題2は完成までには至りませんでしたが、現場の作業を1つでも多く行い、最高でした!上記にある課題1を完成に至るまでの過程でのデータの取得、配置、効率化を考察してきたことと、課題2での失敗からのコード読解で処理の理解を深めることができたからです。

過程を理解して簡略化することにより、全ての作業効率をあげることができるのをここまでのインターン活動で深く知ることができました。今回の活動と今後行うインターン活動、普段の作業から成長した自分を9月にあるゲームジャムで証明していきたいと思います。

www.slideshare.net

 

成果報告資料(slideshareには代理で登録しています)

インターンでクライアントエンジニアを体験しました

$
0
0

はじめまして。ハチナイのクライアントエンジニアインターンとしてお世話になりました、AxIと申します。
今回15日ほどハチナイの開発としてお邪魔させていただきました。
僕はゲーム開発は初めてだったのですが今回のインターンで、自分で改善点を見つけて、ある程度実装するところまで経験させていただきました。

目次

インターン開始前

一週間前に説明をいただき、UnityとGitの復習を行いました。

インターン開始

まずは改善点の探索ということで、仕様書を20時間ほど読み、仕様書で与えたいユーザー体験と僕が自分でプレイして経験した体験のどこにギャップがあるのかを考えました。また、1ユーザーとして不便なところやわかりにくいところを考えリストアップしました。
それらの改善点を抜粋し、開発チーム内の様々な職種の方のまえで発表とディスカッションを行い、理にかなっている物の中でインターンという短い時間の中で可能な改善点を選定しました。

課題決定

取り組む課題は、デレストのカード詳細のユーザーフレンドリーな確認方法の実装としました。
従来、デレストオーダー編成時、サポート選択時にはアクションカードの効果を三つ以下の小さなアイコンで理解しなければならなく、特に初心者にとっては難しい環境でした。(対象カードを所持しているキャラアイコンを長押しすると、選手詳細から説明文をみることが可能)
そのため、それらの画面で軽いアクションで確認できる機能は、初期ユーザーのデレストへのハードルを下げる、中長期ユーザーのオーダー編成時の煩雑さを下げるという点でメリットが期待されました。

実装

あまり触れたことのないUnityの2D周り(3Dは経験あり)、Git、ゲーム開発という環境で不安でしたが、社員さんの優しいサポートの元、牛歩ではありましたが実装を進めました。
インターン中にすべてのコード理解は不可能と感じたため、まだ見ぬ他の機能を阻害しないように基本的に現状の機能内に似た機能を探し、その実装方法を真似て実装するというカメレオン的なコーディングを意識しました。

初期想定ではカードタップ時にポップアップ表示、ポップアップ表示時にポップアップ以外タップでポップアップ消去という機能でしたが、実際に実機で触れてみたところ、ポップアップ消去動作が煩雑であったため、カードに触れている間のみポップアップを表示という機能に変更しました。
このように実機でなんどもビルドし、ユーザーの邪魔にならないポップアップの表示方法を検討しました。

f:id:AxI:20190628174437p:plain
実装結果
実装の詳細は成果発表の時に使ったスライドの抜粋として、末尾に添付しておきます。

インターンを終えて

反省点

迷惑をかけたくないという感情が強すぎ、自分でできる可能性があるところはとことん遠慮がちになってしまい逆に迷惑をかけてしまったように感じました。
配慮と遠慮の区別をつけられるよう今後精進したいです。

良かった点

仕様書を読んで改善点をプレゼンし、仕様書を書いて実装して、実機で動かして、使ってみて使ってもらって、改善して。と一連の流れを体験できたのは、ゲーム業界未経験の僕にとってかなり価値のあるものだったと思います。
また、問題提起や発表、コーディングは好評をいただけました。
問題提起や発表は学問や研究と繋がる面が多々あったので、普段頑張っていることが社会に出ても役に立つ実感ができてとても嬉しかったです。
コーディングも実務は未経験でしたが、実装をしていく中で授業や研究で学んできたことがしっかり役に立ってる感が味わえ、今後卒業に向けた研究へのモチベーションにもつながりました。

タイミングが良かった

アカツキの9周年祭、ハチナイ の2周年祭がインターン中にあり、インターン生ながら参加させていただきました。

f:id:AxI:20190628173036j:plain
かわいいケーキ
インターン生だろうが関係なく受け入れていただいた面や、ハチナイのお祝いに他の部署の人たちが御祝品もって突入してくる雰囲気はとても暖かでした。

成果発表の時に使ったスライドの抜粋

f:id:ytfkbc:20190729115421p:plainf:id:ytfkbc:20190729115700p:plainf:id:ytfkbc:20190729115718p:plainf:id:ytfkbc:20190729115726p:plainf:id:ytfkbc:20190729115736p:plainf:id:ytfkbc:20190729115745p:plainf:id:ytfkbc:20190729115754p:plainf:id:ytfkbc:20190729115803p:plainf:id:ytfkbc:20190729115830p:plainf:id:ytfkbc:20190729115839p:plainf:id:ytfkbc:20190729115922p:plainf:id:ytfkbc:20190729115930p:plainf:id:ytfkbc:20190729115940p:plainf:id:ytfkbc:20190729115951p:plainf:id:ytfkbc:20190729115959p:plainf:id:ytfkbc:20190729120007p:plainf:id:ytfkbc:20190729120018p:plainf:id:ytfkbc:20190729120027p:plainf:id:ytfkbc:20190729120038p:plainf:id:ytfkbc:20190729120048p:plainf:id:ytfkbc:20190729120059p:plainf:id:ytfkbc:20190729120120p:plainf:id:ytfkbc:20190729120130p:plainf:id:ytfkbc:20190729120139p:plainf:id:ytfkbc:20190729120153p:plainf:id:ytfkbc:20190729120203p:plainf:id:ytfkbc:20190729120238p:plainf:id:ytfkbc:20190729120250p:plainf:id:ytfkbc:20190729120301p:plainf:id:ytfkbc:20190729120329p:plainf:id:ytfkbc:20190729120340p:plainf:id:ytfkbc:20190729120353p:plainf:id:ytfkbc:20190729120407p:plainf:id:ytfkbc:20190729120419p:plain

クライアントエンジニアインターンでUX/UI改善した話

$
0
0


こんにちは、ritoという者です。

この度、クライアントエンジニアとして3週間の就業型インターンシップに参加し、八月のシンデレラナインのUX/UI改善のために尽力させていただきました。

このインターンシップでは、僕が希望したこともあり、既に挙がっている要件を実装するのではなく改善策を提案するところから経験することができました。
本稿では僕が取り組んだ課題を決めるまでの流れと、改善案の実装について書ける範囲で書いていこうと思います。

課題決めと改善案

自分で遊んでみないことには改善案なんか出せません。

僕はハチナイをプレイしたことがなかったので
インターンが始まるまでの2週間強、暇さえあればアプリを起動して遊んでいました。

初心者ながら遊んでいてこのゲームの中で一番面白いと感じたのがデレストでした。

デレスト(シンデレラストーリー)とは
ハチナイにおいてキャラにスキルを覚えさせるためのカードゲームで、
ゲーム内で取得したポイントが所定の値に達したらスキルを習得させられるといったものです。
種々のストーリーにはそれぞれ特殊なギミックがあり、
個人的には各ギミックに応じてデッキの編成や手札を切る戦略を考えるのが、このゲームの醍醐味だと思いました。

しかし、遊んでいて思ったのが

スキルを覚えさせたいキャラが決まっているときに、
そのキャラに合わせてデッキ(オーダー)を編成しデレストを始めるまでの画面遷移が煩雑だ

ということです。

画面遷移が煩雑なあまり、
戦略を練って編成して挑戦し、また戦略を練って編成し…というサイクルを回すのが億劫になってしまいました。

そこで今回のインターンシップではこの画面遷移を簡潔化するという課題を設定しました。

細かい説明は省かせていただいて、図でお見せすると

f:id:ritoaktsk:20190828215903p:plain

デレスト開始までの画面遷移(改修前)

↑これを…

f:id:ritoaktsk:20190828220039p:plain

デレスト開始までの画面遷移(改修後)

↑こうしよう…という提案をしました。

オーダー確認画面を撤廃し画面遷移を簡潔化するのに伴って、オーダー編成画面のデザインや機能にも変更を加えました。
この変更により、ゲーム開始までの必要タップ数、画面遷移数が減少し、オーダーの一覧性が向上します。

f:id:ritoaktsk:20190828220256p:plain

オーダー編成画面の変更点

実装

話し合いを重ねて改善案の仕様を決めるのと並行して、2日ほどかけてじっくりソースコードを読み込みました。

「画面遷移を簡潔化する」

言うは易し、とはまさにこのことだと痛感しました。

画面間のデータの渡し方ひとつ取っても、
同一シーンでのビューの切り替えなのか、はたまたシーンを新たに読み込んでいるのかで
処理は大きく異なりましたし、

デレストへはホーム画面からだけでなくチーム強化からも来られるので、1つの変更が全く別の画面にまで波及することも十分にあり得ました。

とはいえ技術的にものすごくチャレンジングなことをしているわけではなかったので、
最終的にはなんとか形にはできました。
技術的な挑戦があったというよりかは、可読性・保守性に配慮したコーディングができているかといったエンジニアとしての基礎力を磨くことができたと思います。
エンジニアとしてまだペーペーの僕には非常にありがたい経験でした。

インターンを終えた感想

今回のインターンシップでは
ひとりのユーザとしての感想や仕様書、ToDoリストの内容を踏まえて自分で改善案を考え、プレゼンし、仕様を詰め設計して実装するという一連の流れを経験することができ、
大変有意義な時間を過ごせたと思います。

特に改善案のプレゼンでは好評をいただき、自分で取り組むことになった案以外にも多数、今後やるべきタスクとして採用していただけました。
大学での研究で培った経験が活きたのを実感することができ嬉しかったのを覚えています。

ただやはり上手くいかなかったことも多くあり、
中でも一番の反省点は全体的にあまりにも消極的あるいは受け身だったことです。

周りの社員さん方が忙しそうなのであれば、積極的に自分なりにできることを探したり、インターン中にはあまり関わることがない別部署の見学をさせていただいたり、色々とやりようはあったと思います。

そんな引っ込み思案な僕に対しても皆さん快く接してくださりましたし、
開発チームのメンバーで行ったお食事や1on1ミーティングなどでは、
趣味や雑談、ゲーム業界や技術の話はもちろんのこと、
僕の就職や将来についての悩み・相談事にも親身に付き合ってくださりました。
おかげで朧げだったやりたいこと・これからすべきことがはっきりしてきました。

初めてのインターンで、始まる前は不安もありましたが、ここに来れてよかったです。
お世話になったメンターさんをはじめ、サポートしていただいた開発チームの皆さんや、人事・総務の皆さんに、この場をお借りして改めてお礼申し上げます。

3週間ありがとうございました。

Viewing all 223 articles
Browse latest View live