READYFOR Tech Blog

READYFOR のエンジニアブログ

東大松尾研の「GCIデータサイエンティスト育成講座」を修了しました

はじめに

はじめまして。浦野昌平 ( @s_runoa ) です。 READYFOR株式会社でエンジニアとして働いています。 コロナの影響で授与式兼交流会が延期になったため修了証はまだありませんが、先月末に東大の松尾研が主催しているGCIデータサイエンティスト育成講座を修了しました。 今回はその参加レポートを書いていきます。

講座について

READYFOR最初期の投資家でもある東大の松尾先生が主催の講座です。 今回は駒場キャンパスとオンラインで同時開催された社会人も参加できる講座に参加しました。

gci.t.u-tokyo.ac.jp

カリキュラム

カリキュラムはこのように組まれていました。 1週間に1,2章ずつ学習し、各章に演習課題や宿題があります。 講座ではすべての宿題をクリアすることが修了条件の一つになっており、1日1,2時間程度の勉強時間を確保して進めました。

1. 本講座の概要とPythonの基礎
2. 科学計算、データ加工、グラフ描画ライブラリの使い方の基礎
3. Pythonによる科学計算(NumpyとScipy)
4. Pandasを使ったデータ加工処理
5. Matplotlibを使ったデータ可視化
6. 統計・確率
7. 機械学習の基礎(教師あり学習)
8. 機械学習の基礎(教師なし学習)
9. モデルの検証方法とチューニング方法
10. データサイエンティスト中級者への道

また後半にはコンペや総合課題がありました。 コンペではKaggleを模した形式になっており、実際のデータを分析して他の生徒とスコアを競います。 でもSlackでお互いの気付きや悩みを共有し合ったり、定期的に公開されるお互いのスコアをみて自分のアルゴリズムに足りないところを考えるなど、ただ競うだけに留まらない学びがありました。

本家Kaggleにもそのような議論し合う場があり、有益な情報にはポイントが入る仕組みになっているそうです。 ひたすら自分が一番を目指すのではなく、参加者全員がデータへの理解を深めつつスキルアップしていける優れた仕組みだと感じました。 元々、プログラマー界隈には学びを共有しつつお互いに成長していく文化がありますが、賞金のかかったコンペでもそれを再現できるのは業界の強みですね。

学習環境

学習環境にはハンズオン型AI人材育成サービスであるiLectを使いました。 Jupiter Notebook同様に教科書とプログラムエディタとプログラムの実行環境が一体化した構成になっており、教科書を読んでその場で実行できます。 オンラインのプログラミング学習サービスも教科書を見ながら学習できるように工夫されていますが、より強い一体感がありました。 とてもハードル低く自然と学習できるためプログラミング未経験の人にもお勧めです。

www.ilect.net

質問はオンラインでSlackを通じて行います。 基本的には教材が配られて自習する形式ですが、スクールのメンターと生徒が入ったチャンネルで生徒たちが自由に質問したり意見交換したりしていました。

また様々な分野の専門家を招いたオンラインの講座、自由参加のもくもく会も開催されていましたし、修了後は松尾先生による講義も予定されているので楽しみです。

f:id:srunoa:20200421204403p:plain
iLect

こんな人におすすめ

プログラミング経験に関わらず、機械学習に興味のあるなら誰でもお勧めできる講座です。 機械学習を早く身につける意味ではプログラミング経験があるに越したことはありませんが、身につけた技術を生かそうとするとビジネス的な考え方が必ず必要になります。 なのでビジネス的な考え方を身につけた人がこの講座で技術を手に入れることでより深く仕事に生かせるのではないかと思いました。

実際にやってみるには

今は受講生の募集は特にしていないようです。

gci.t.u-tokyo.ac.jp

でも実はこの講座で使っている教材はこちらのページで無料公開されてるため、誰でも勉強することができます。 (演習課題とコンペを除く)
※ただしこちらの教材はダウンロードページに書かれている通り、個人で学習する目的のみで利用可能となっているのでご注意ください。講習会・教室での利用や企業内での講習など、商用での利用は認められていません。

weblab.t.u-tokyo.ac.jp

iLectを使うことはできませんが、例えばGoogleが無料で公開しているJupyterノートブック環境であるColaboratoryで同様に動かすことができます。

colab.research.google.com

準備

まず上記ダウンロードサイトからZipファイルをダウンロードして.ipynbファイルを確認しましょう。 これがJupyter Notebookで使うファイル形式です。 このファイルをGoogle DocsにアップロードするとColaboratoryで開くことができます。

f:id:srunoa:20200421204718p:plain
Colaborator

簡単な使い方

開くとこのような画面が出てきます。 上で書いたようにColaboratoryではコードとテキストが一体化しています。 この画像の赤枠がコードセル、青枠がテキストセルです。 テキスト部分が教科書、コード部分が実践です。 コードの隣の▶を押すことで実行し、すぐ下にその結果が出てきます。

テキスト部分を読んで理論を学び、コード部分を実行して動きを確認するという流れで効率的に勉強できるので、興味があれば試してみてください。

実際にデータを分析するときにもこのエディタを使い、データ読込用のセル、データの特徴抽出用のセル、学習用のセルのように整理して使います。 普段プログラミングをするときもコード内に適宜コメントを挟みますが、このエディタを使うと学習の仕組みをより丁寧に説明することができます。

f:id:srunoa:20200421204744p:plain
Colaborator

今後

今回、この講座を通じて機械学習に必要な考え方や基礎的な技術を学ぶことができました。 これからは私も会社のデータを機械学習を使って分析したり、Kaggleに挑戦したりして社会に貢献していきたいです。

コロナが流行る中でアメリカホワイトハウスがKaggleで賞金ありの分析コンペを公開するなど、世界中で分析の需要は高まっています。 一部SNSでは "医療の素人であるデータサイエンティストが未曾有の危機に対して口出しするな" という意見も見られました。 でも個人的には、一人の専門家では処理できないほど多くのデータを元に分析するからこそ、見えてくるものもあるのではないかと期待しています。

最後に、このような講座を無償で提供し、教材の作成や運営をして頂いた関係者の皆さんに感謝いたします。 ありがとうございました。

READYFORにおけるSlackのチャンネル活用方法を紹介します!

こんにちは、コーポレートエンジニアの佐々木です。

READYFORでは、社内コミュニケーションツールとして「Slack」を採用しています。
Slackのチャンネル運用についても活用の方法を社内に発信しており、その一部をご紹介します。

パブリックチャンネルでのオープンなコミュニケーション

Slackでのコミュニケーションは、基本的にパブリックチャンネルでのやりとりを推奨しており、チャンネル数も400件以上あります。
パブリックチャンネルの参加は自由で、退出も自由です。チャンネルの作成は自由ですが、運用が変わった時点で見直しを行い、使わなくなったチャンネルはアーカイブすることを促しています。
また、使われなくなったチャンネルについても、3ヶ月投稿がないチャンネルはアーカイブされるようにしています。

チャンネルアーカイブ
チャンネルアーカイブがされます

READYFORでは、Slackのチャンネルを大きく4つに分類しています。

  • 全社チャンネル

  • 部門・チームチャンネル

  • 組織横断チャンネル

  • システム通知チャンネル

全社チャンネルはメンションの使い方に注意

全メンバーがチャンネルに入っていることを前提とした通知・コミュニケーションが行われるチャンネルです。このチャンネルは、社内の全員へ通知がされるということから、チャンネル数を少なくし、発信の方法にも注意を払っています。

  • #all-announcement は、人事・評価制度の改定、経費精算方法の変更など、全メンバーにインプットがなされないと業務影響を及ぼす可能性がある情報が投稿されます

  • #all-general は、サービス・プロダクトのアップデート情報や朝会の議事録など、全メンバーが把握することを推奨する情報が投稿されます

チャンネルへの投稿は、即時性を求めない場合メンションは付けない方が、落ち着いて読まれる可能性が高くなります。 @here@channel など、たくさんメンションがされると、通知に反応してメッセージを開き、中身がしっかり読まれないケースが増えます。その結果、お願いしたいことが実行されなくなってしまうことに繋がります。また、他の重要な情報が流れないよう、簡潔に要旨を絞った投稿とすることも大切です。

全社チャンネルでのメンションの使い方
全社チャンネルでのメンションの使い方

部門・チームチャンネルは情報を受け取るべきメンバーごとに

部門やチームのメンバー内でコミュニケーションが行われるチャンネルです。それぞれ共通の略称を細かく決めて、接頭辞につけてチャンネルを作成しています。
部門・チームのチャンネルは、レスポンスしやすいよう、所属部門の細かなユニットなど情報を受け取るべきメンバーごとでのチャンネル作成を推奨しています。また、同じメンバーでのやりとりは同じチャンネルとして、出来るだけコンテキストごとに細かくチャンネルを分けない方が、チャンネルの切り替えも少なく、コミュニケーションがとりやすくなります。

  • READYFORで使われている部門略称例
略称 部門
dev 開発
pr 広報
legal 法務・コンプライアンス
  • チームチャンネルの様子
    エンジニアリンング部門バックエンドチームのチャンネル
    エンジニアリンング部門バックエンドチームのチャンネル

業務外のコミュニケーションも組織横断チャンネルで

組織横断チャンネルは、他部門への要望・依頼等 、組織を横断するコミュニケーションを行うチャンネルです。
Slackでは、チャンネルをアルファベット順に並べることができるため、他部門へのリクエストを行うチャンネルの接頭辞を #req- に統一して、明確にチーム内のコミュニケーションと分けることで、投稿するチャンネルを迷いにくくしています。
また、社内イベントなど、部門やチームを超えて有志のメンバーが集まってコミュニケーションをとりたい時にもチャンネルを活用しています。

表記方法 用途 チャンネル例
req-[〇〇] 他部門への作業依頼・要望等を行う req-corpsys
pj-[〇〇] 部門・チームには紐づかない一時的な社内の人の集まり pj-忘年会2019
grp-[〇〇] 部門・チームには紐づかない恒久的な社内の人の集まり #grp-onboarding

リクエストチャンネル
コーポレートシステム部へのリクエストチャンネル

また、業務外の雑談的なコミュニケーションもとても活発です。 #enjoy-[〇〇] チャンネルには、趣味や共通の話題、学びを深めたい分野ごとにチャンネルがあります。
#times-[name] チャンネルでは、個人が自由に想ったことを発信しています。そこでの話題が派生して、業務に繋がることもあります。

表記方法 用途 備考
times- 個人のやっていること(分報、日報)、気づきなど
enjoy- 楽しいチャンネル・業務以外の話をしたいとき
学ぶ系はenjoy-study-XX

楽しいチャンネルもあります

システム通知チャンネルは、用途や情報の優先度に応じて

Slack以外のツールやサービスと連携して、システム通知を行うチャンネルです。チームごとに、用途や情報の優先度に応じて、通知されるチャンネルを分けるなどしています。また、全社で利用しているツールとも連携していて、業務の中で発生する通知に気付きやすいようにしています。

  • 全社員任意のシステム通知は、 #[システム名]

  • 部門固有のシステム通知は、 #<部門略称>-[システム名]

システム通知チャンネルの一部を並べてみる

これまでは?

以前は、LINE、Facebook、メール、Slack等で社内コミュニケーションを取っていたため、情報が混在していました。2019年4月ごろに、社内コミュニケーションツールをSlackに一本化し、チャンネル名の命名規則をつくるなどして運用を開始しました。
その後、組織拡大に伴い、やりとりされる情報量も社内で扱われる情報の種類も増えてきたことから、チャンネル数も指数関数的に増加傾向にありました。そんな中、Slackでのコミュニケーションに対して、社内でいくつか問題が起り始めました。

社内で起きていた問題

そこで、改めて個々人が「必要な情報が優先してインプットされる状態」となり、その上で「必要なときには欲しい情報が取りにいける状態」を目指し、Slackのチャンネル活用の方法を見直しました。

まとめ

READYFORではこのようなチャンネル整理で、Slackを活用しています!
日常的なコミュニケーションは、組織のフェーズや文化によっても常に変化していきますが、ストレスなく円滑なコミュニケーションが行えるよう、情報を受け取る側も、情報を発信する側も、お互いに配慮しあえるルールがあるといいですね。

Terraform のテストを Golang で書く!

こんにちは。READYFOR 株式会社で SRE として働いている ジェダイ・パンくず🚀 と申します。

突然ですが、皆さんの現場ではインフラのテストの仕組みは導入済みですか?我々はまだ出来ていません(笑)。

READYFOR では IaaS として AWS を、IaC として Terraform を導入しているのですがコードのテスト・コードによってデプロイされた状態のテストを何かしらの仕組みを使って実践したいなぁと考え、今調査している最中です。

今回は Terraform のテストを書くツール Terratest について調べた内容を皆さんに共有したいと思っています。また AWS の状態をテストする仕組みとしてよく知られている Awspec との比較も行っていきたいと思っています。

必要になるモノ

事前に必要になるソフトウェアの一覧です。

  • Golang (requires version >= 1.13)
  • Ruby (required by Awspec)
  • Awspec

今回ターゲットにする AWS インフラと Terraform コード

任意の VPC, サブネット上に ECS クラスタ・サービス・タスクを作る Terraform コードを前提にテストを実施していきたいと思います。VPC やサブネットは事前に作成したモノを利用 (terraform の data や variable を用いる) します。

今回 AWS インフラをデプロイするために用意した main.tf と output.tf です。(ID などはマスクさせて頂きました) Terratest のテストを行う際に事前に AWS インフラがデプロイされている必要は無いためここでは terraform apply しません。

main.tf

terraform {
  required_version = ">= 0.12"
}

# ------------------------------------------------
# variables の設定
# ------------------------------------------------
variable "vpc_id" {
  default = "****"
}

variable "cluster_name" {
  description = "example"
  type        = string
  default     = "example"
}

variable "service_name" {
  description = "example"
  type        = string
  default     = "example"
}

# ------------------------------------------------
# 既存 Resource の指定
# ------------------------------------------------
data "aws_vpc" "example" {
  id = var.vpc_id
}

data "aws_subnet_ids" "all" {
  vpc_id = data.aws_vpc.example.id

  filter {
    name   = "tag:Name"
    values = ["rf-sandbox-***-private0-sb", " rf-sandbox-***--private0-sb"]
  }
}

# ------------------------------------------------
# 新規 Resource の作成
# ------------------------------------------------
resource "aws_ecs_cluster" "example" {
  name = var.cluster_name
}

resource "aws_ecs_service" "example" {
  name            = var.service_name
  cluster         = aws_ecs_cluster.example.arn
  task_definition = aws_ecs_task_definition.example.arn
  desired_count   = 0
  launch_type     = "FARGATE"

  network_configuration {
    subnets = data.aws_subnet_ids.all.ids
  }
}

resource "aws_ecs_task_definition" "example" {
  family                   = "terratest"
  network_mode             = "awsvpc"
  cpu                      = 256
  memory                   = 512
  requires_compatibilities = ["FARGATE"]
  execution_role_arn       = aws_iam_role.execution.arn
  container_definitions    = <<-JSON
    [
      {
        "image": "terraterst-example",
        "name": "terratest",
        "networkMode": "awsvpc"
      }
    ]
JSON
}

resource "aws_iam_role" "execution" {
  name               = "${var.cluster_name}-ecs-execution"
  assume_role_policy = data.aws_iam_policy_document.assume-execution.json
}

resource "aws_iam_role_policy_attachment" "execution" {
  role       = aws_iam_role.execution.id
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

data "aws_iam_policy_document" "assume-execution" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ecs-tasks.amazonaws.com"]
    }
  }
}

output.tf

output "task_definition" {
  value = aws_ecs_task_definition.example.arn
}

Terratest のテストを書いてみる

テストを書く

次に Terratest のテストを書いていきます。

package test

import (
    "fmt"
    "testing"

    "github.com/gruntwork-io/terratest/modules/aws"
    "github.com/gruntwork-io/terratest/modules/terraform"

    awsSDK "github.com/aws/aws-sdk-go/aws"
    "github.com/stretchr/testify/assert"
)

func TestTerraformAwsEcs(t *testing.T) {
    t.Parallel()

    expectedClusterName := fmt.Sprintf("example")
    expectedServiceName := fmt.Sprintf("example")

    // テストで起動するリージョンを複数指定し、どのリージョンでも起動することを確認する
    // awsRegion := aws.GetRandomStableRegion(t, []string{"us-east-1", "ap-northeast-1"}, nil)
    awsRegion := "ap-northeast-1"

    terraformOptions := &terraform.Options{
        TerraformDir: "../",

        Vars: map[string]interface{}{
            "cluster_name": expectedClusterName,
            "service_name": expectedServiceName,
        },

        EnvVars: map[string]string{
            "AWS_DEFAULT_REGION": awsRegion,
        },
    }

    defer terraform.Destroy(t, terraformOptions)

    if _, err := terraform.InitE(t, terraformOptions); err != nil {
        fmt.Printf("Terraform Init Error.")
    }

    if _, err := terraform.ApplyE(t, terraformOptions); err != nil {
        fmt.Printf("Terraform Apply Error.")
    }

    taskDefinition := terraform.Output(t, terraformOptions, "task_definition")

    // 各テスト (次項 "各テストの説明" を参照のこと)

    // (1) クラスタ周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.Cluster.html
    cluster := aws.GetEcsCluster(t, awsRegion, expectedClusterName)
    assert.Equal(t, int64(1), awsSDK.Int64Value(cluster.ActiveServicesCount))
    assert.Equal(t, expectedClusterName, awsSDK.StringValue(cluster.ClusterName))
    assert.Equal(t, int64(0), awsSDK.Int64Value(cluster.PendingTasksCount))

    // (2) ECS サービス周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.Service.html
    service := aws.GetEcsService(t, awsRegion, expectedClusterName, expectedServiceName)
    assert.Equal(t, int64(0), awsSDK.Int64Value(service.DesiredCount))
    assert.Equal(t, "FARGATE", awsSDK.StringValue(service.LaunchType))
    assert.Equal(t, expectedServiceName, awsSDK.StringValue(service.ServiceName))
    assert.Equal(t, "LATEST", awsSDK.StringValue(service.PlatformVersion))

    // (3) ECS Task 周りのテスト
    // Reference: https://docs.aws.amazon.com/ja_jp/sdk-for-go/v1/api/service.ecs.TaskDefinition.html
    task := aws.GetEcsTaskDefinition(t, awsRegion, taskDefinition)
    assert.Equal(t, "256", awsSDK.StringValue(task.Cpu))
    assert.Equal(t, "512", awsSDK.StringValue(task.Memory))
    assert.Equal(t, "awsvpc", awsSDK.StringValue(task.NetworkMode))
}

コードの説明をしていきます。

  • import 行で 'terratest' と 'testify/assert' をロードしています
  • expectedClusterName, expectedServiceName で期待するクラスタ名・サービス名を記しています
  • awsRegion でテストの際に AWS インフラをデプロイするリージョンを指定しています
  • defer でテストが終わった後の処理として Destroy することを明記しています
  • ECS クラスタ・サービス・タスク毎にテストが記されています (次項)

各テストの説明

assert 文で Terraform によってデプロイされた AWS インフラの状態でテストしています。ここではそれぞれのテストの意味を説明していきます。

(1) ECS クラスタ

テストされるモノ 期待値
アクティブな ECS サービス数 1
ECS クラスタ名 expectedClusterName
ペンディングタスク数 0

(2) ECS サービス

テストされるモノ 期待値
ECS DesiredCount 0
ECS ローンチタイプ 'FARGATE'
ECS サービス名 expectedServiceName

(3) ECS タスク

テストされるモノ 期待値
タスク定義で記されている CPU ユニット数 256
タスク定義で記されているメモリ量 512
タスク定義で記されているネットワークモード 'awsvpc'

テストの記述方法

テストの1行をピックアップしてテストの書き方について説明します。

assert.Equal(t, int64(1), awsSDK.Int64Value(cluster.ActiveServicesCount))

整数値: 1 と awsSDK.Int64Value(cluster.ActiveServicesCount) が同一であることをテストしている行ですが、cluster.ActiveServicesCount はどの様に知れば良いでしょう?答えとしては 'aws-sdk-go' のドキュメント (下記: クラスタ・サービス・タスク) を確認しつつテストを書いていく作業が必要になります。(この時にエディタの補完機能を使っていると容易に導き出せます)

テストの実行

上記で書いたテストを test ディレクトリに配置します。ディレクトリ構造は下記のようになります。

.
├── main.tf
├── output.tf
└── test
    └── terraform-aws-ecs_test.go

では go コマンドを使ってテストを実行します。

cd test
go mod init test
go test

結果、全てのテストが終了すると結果の末尾に下記のようなログが出力されます。この時に terraform apply, テスト実行, terraform destroy が処理されるので、テスト完了までしばらく待つ必要があります。

PASS
ok      test    80.068s

失敗するケースとして誤ったテストを書きテストを実行すると下記のようなログが得られます。

--- FAIL: TestTerraformAwsEcs (91.04s)
    terraform-aws-ecs_test.go:60:
                Error Trace:    terraform-aws-ecs_test.go:60
                Error:          Not equal:
                                expected: "511"
                                actual  : "512"

                                Diff:
                                --- Expected
                                +++ Actual
                                @@ -1 +1 @@
                                -511
                                +512
                Test:           TestTerraformAwsEcs
FAIL
exit status 1
FAIL    test    91.344s

上記の場合、ECS タスクに定義されたメモリ量が期待したものと異なっていたとエラー出力されています。

Awspec のテストを書いてみる

Awspec は国内のエンジニアの方が開発した AWS 状態をテストするツールです。海外の技術ブログやコードの中にも最近は登場するようになりました。今回 AWS インフラをデプロイするために用いた Terraform のコードに沿って Awspec テストを書いてみました。

require 'spec_helper'

describe ecs_cluster('example') do
  it { should exist }
  it { should be_active }
end

describe ecs_service('example'), cluster: 'example' do
  it { should exist }
  it { should be_active }
  its(:cluster) { should eq 'example' }
  its(:service_name) { should eq 'example' }
  its(:service_arn) { should eq 'arn:aws:ecs:ap-northeast-1:********:service/example' }
  its(:cluster_arn) { should eq 'arn:aws:ecs:ap-northeast-1:********:cluster/example' }
  its(:desired_count) { should eq 0 }
  its(:pending_count) { should eq 0 }
  its(:running_count) { should eq 0 }
end

describe ecs_task_definition('terratest') do
  it { should exist }
  it { should be_active }
  its(:family) { should eq 'terratest' }
end

※ awspec の Resource Type 'ecs_service' のドキュメントによると上記のような記述は書けませんが、, cluster: 'exmaple' を追記してテストを実施することが実際には出来ました。今回も main.tf でデフォルトではないクラスタを作成しているので上記のように記述しています。尚、awspec のドキュメントに対して下記の通り PR をしておきました。

github.com

Terratest, Awspec のテストを比較・考察

両者ともに Terraform のデプロイを行った結果としての AWS インフラの状態をテストしているツールだということがわかりました。Awspec に関しては Resource Types の開発が追いつかないとそもそもテストが書けませんが、Terratest は AWS 公式のライブラリ 'aws-sdk-go' に沿ってテストを書くのでその心配は必要なさそうです。また Terratest は Terraform によるデプロイとテスト、その後のインフラの削除まで自動で行ってくれるツールですが Awspec は Terraform でデプロイした結果をテストするツールということで、その辺りの違いもあるようです。また Terratest は Terraform コードの output 文で得られた値もテストに利用できます。

一方で Awspec は Test-Kitchen (https://github.com/test-kitchen/test-kitchen) と Test-Kitchen の Terraform Driver である Kitchen-Terraform (https://github.com/newcontext-oss/kitchen-terraform) と組合せて、下記の URL にあるようなことも出来るようです。

Terraform デプロイし tfstate の状態と同一になっているかテストする例

これは 'terraform-aws-modules/terraform-aws-eks' という EKS の Terraform Module なのですがその中のファイル 'test_eks.rb' で下記のように記述されていて

require 'awspec'

# rubocop:disable LineLength
state_file = 'terraform.tfstate.d/kitchen-terraform-default-aws/terraform.tfstate'
tf_state = JSON.parse(File.open(state_file).read)
region = tf_state['modules'][0]['outputs']['region']['value']
ENV['AWS_REGION'] = region

これは Terraform デプロイした結果として得られる tfstate ファイルの通りに AWS インフラがデプロイされているかどうかを Awspec でテストしているように見えます。(まだ手元で動かしたわけではないので間違っていたら指摘頂けると助かります)

また、このテストを実行している .kitchen.yml ファイルは下記のようになっています。

---
driver:
  name: "terraform"
  root_module_directory: "examples/basic"

provisioner:
  name: "terraform"

platforms:
  - name: "aws"

verifier:
  name: "awspec"

suites:
  - name: "default"
    verifier:
      name: "awspec"
      patterns:
      - "test/integration/default/test_eks.rb"

まとめ

Golang でテストを書くのか Rspec DSL でテストを書くのか、それによって選定してもいいですし、CI/CD のパイプラインの中でテストをどう自動実行するかを考慮して選定してもいいと思います。READYFOR では CI/CD に CodeBuild, CodePipeline を使っているので、その中でどう処理出来るのか、これから検討していきたいと思っています。

ベーシックさんとの合同LT会に参加しました!

こんにちは、エンジニアリングマネージャーの岡村です。

1月31日 、マーケティングとテクノロジーで課題解決をする株式会社ベーシックとREADYFORとの合同LT会に参加しました。そのレポートをお届けします。

f:id:resqnet:20200219173022j:plain

弊社エンジニア森さんの古巣ということでベーシックが開催している社内LT会にお邪魔させていただくかたちで実現しました。
ベーシックのみなさんはフロントエンド・バックエンドなど役割を持たずなんでもこなす、つよつよエンジニア集団。 今回のLT会では、モダンな技術を紹介してくださいました!

開会

まずは、お互いの会社を紹介するところから、LT会が始まりました。

f:id:resqnet:20200219173157j:plain

LT会内容

・ベーシック - タインさん [PSSRとは?] f:id:resqnet:20200219171119j:plain

PSSRとは?をテーマに、CSRとSSRの違いから丁寧に説明してくれて、とてもわかりやすかったです。
動作した時のイメージアニメーションもありスライドも凝っていました。

・READYFOR - いとひろさん [技術的負債をエンジニア以外にも説明できるようになろう] f:id:resqnet:20200219172012j:plain

技術的負債をエンジニア以外にも説明できるようになろうというテーマで、弊社のエンジニアリング部門を統括する伊藤博志(いとひろ)さんが話しました。 貸借対照表の説明がわかりやすく、「技術的負債も資産だ」という話が印象に残っています。 負債は必ずしも悪ではないが、返済計画は大事。

・READYFOR - 安本さん [3700行のモデルをリファクタリング] f:id:resqnet:20200219172123j:plain

弊社バックエンドエンジニアの安元さんは、スピード重視の開発で溜まった技術的負債をリファクタするためにテストを書いています。

6000行のテスト書いたとのこと感謝しかないです。 安元さんおすすめのテストをサポートしてくれるGem はこちら。 →rspec-kickstarterhttps://github.com/seratch/rspec-kickstarter

・ベーシック - CCさん [WASMの話] f:id:resqnet:20200219172549j:plain

フロントエンドの歴史からWASMまでを振り返って、WebAssemblyはどういう技術なのかを伝えていただきました。 歴代のブラウザアイコンや技術に懐かしさを感じつつ、理解が深まりました。
WebAssemblyの課題は、セキュリティ懸念と実行速度 にあるとのこと。

・READYFOR - 江面さん [AtomicDesignと汎用UIコンポーネント集の両立] f:id:resqnet:20200219172604j:plain

デザインシステムをどう作ったかという話 を中心に、 ReactOnRailsは便利だけど実装で苦労することなどについて共有してくれました。

弊社フロントエンドでよく出てくるワード「application-awareかどうか?」 そのうち技術ブログで書きたいです。

・ベーシック - 桜庭さん [カメラで遊んでみた] f:id:resqnet:20200219172619j:plain

カメラでとった画像をドット絵に変換するアプリを作ったという話。 フロントもバックもGoで作っていて、かなり綺麗にドット絵になっていたことに驚きました。 画像の処理速度などまだまだ課題はありそうとのことです。

懇親会の様子

f:id:resqnet:20200219173208j:plain

それぞれの得意分野や今、取り組んでることなどについて情報交換をして、
懇親会はだいぶ盛り上がり、楽しかったです。

まとめ

READYFORは今ある課題、取り組んでることをメインに話しました。
ベーシックさんは試してみたいことなど興味あることが軸に共有してくれました。 困りごとの共有や相談、あるある話などまた開催したいと思える会になりよかったです!

今後も合同LT会等開催していきたいので、ご一緒してくださる会社さんいらっしゃったらぜひお声がけください!READYFORオフィスでの開催も 検討しております!

ベーシックさん、とても楽しいLT会をご一緒させていただき、ありがとうございました!!

OOCにランチスポンサーとして登壇してきました! #ooc_2020

こんにちは、READYFORでVP of Engineeringをしているいとひろです。

先日2020年2月16日(日)に開催されたObjected-Oriented Conferenceにて、ランチスポンサーとして登壇してきました。

伊藤による発表の様子

ランチセッションでは、「READYFORにおける複雑なドメインとレガシーシステムとの戦い方」 と題してお話ししました。

今回のブログでは、こちらの発表の要点をスライドに併せてお伝えできればと思います。


我々は、「誰もがやりたいことを実現できる世の中を作る」というビジョンのもと、「想いの乗ったお金の流れを増やす」というミッションを持ってサービス開発に挑んでいます。

READYFORのVision・Mission


READYFORは2011年に日本で初めてのクラウドファンディングサービスとして開始以来、約9年間サービス運営をしてきています。

READYFORのクラウドファンディング


そして、昨年のリブランディング/CIリニューアルを経て、クラウドファンディングの枠をこえた「想いをつなぐ金融機関へ」の変化を遂げようというチャレンジの真っ最中です。

READYFORステートメント


では、本セッションの題名にあるREADYFORにおける「複雑なドメイン」とは一体なんなのでしょうか。

READYFORにおける複雑なドメインとは


READYFORのクラウドファンディングサイトを覗いてみると、一見普通のWebサービスのように見えます。どこにドメインの複雑さが隠れているのでしょうか。

READYFORのクラウドファンディング


ここでは、トップページに複数回現れる「プロジェクト」という概念を起点に追ってみましょう。

READYFORのクラウドファンディングのプロジェクト


READYFORのWebサイトを訪れるユーザーのペルソナとしては、大きく分けて「プロジェクト実行者」と「プロジェクト支援者」がいます。

実行者がプロジェクトを始めてから、支援者がプロジェクトを探して支援するまでの、「プロジェクト」のライフサイクルは、Webサイトの裏側に潜む「READYFORシステム」の中に存在しています。(正確にはプロジェクトを探して支援した後にもライフサイクルは続きますが、ここでは簡単のため省略しています)

プロジェクトのライフサイクル


「READYFORシステム」の中身はさまざまな条件に基づく状態遷移を持つワークフローが複雑に絡み合っており、BPMNと呼ばれるモデリング記法で可視化を試みてもなかなかすぐに理解するのは難しいものになっています。

「READYFORシステム」の中身は...?


「プロジェクト」という概念は、READYFORのシステム上でさまざまなコンテキストで扱われます。

「プロジェクト」をめぐるさまざまなコンテキスト


READYFORはサービス開始以来約9年間運営し続けており、「プロジェクトという概念」がさまざまなコンテキストで少しずつ育った結果、

9年間の歴史


「プロジェクトという概念」は3700行に及ぶ、巨大なモデルとして成長しました。

3700行の巨大なモデル


こういった巨大モデルが育ってしまうケースはよく聞く話かなと思いますが、こちらのスライドに挙げているような問題点が挙げられます。

巨大モデルのつらみ


正しい責務分割をするための設計の前段階として、ドメイン駆動設計(DDD)でいうところの「境界づけられたコンテキスト」という概念があります。

境界づけられたコンテキストを理解する


READYFORは現在モノリシックなRuby on Railsのサービスとして実装されていますが、コード上には現れていない、本質的に存在しているであろう境界づけられたコンテキストを理解するために、大きく分けてSoE(System of Engagement)、SoC(System of Control)、SoR(System of Record)の3つの枠の中に当てはまるコンテキストに分けて整理していこうと考えています。

プロジェクトモデルの責務の整理


ここで少し横道にそれます。

SoEやSoRはアーキテクチャー設計をする上でよく知られている概念ですが、SoCは聞きなれないかと思います。実際Chatworkのかとじゅんさんからも以下ような疑問をいただき、Twitterのリプライで補足させていただいたのでご参照ください。

さて、境界づけられたコンテキストを整理していくことで、プロジェクトモデルの責務分割を進めていくための前準備はできそうです。

プロジェクトモデルの責務分割


しかしながら、スタートアップにつきものですが、開発リソースは限られています。われわれは「想いの乗ったお金の流れを増やす」ための新規開発をしていきたいわけなのですが、今このようなプロジェクトモデルの責務分割を進めるためのコストを支払う必要があるのでしょうか?

どうやって進める?


そこで、ビジネス観点としてのコストベネフィットを説明するために、「技術的負債」という概念の説明を試みます。

技術的負債の説明を試みる


「技術的負債」の概念は、もともとウォード・カニンガムリファクタリングの概念を上司に説明するために導入した概念です 。

この概念を拡張して、技術的負債をバランスシートで表現すると、「ソフトウェアの価値」として表層に現れるものと「技術的負債」というエンジニアにしか理解しがたい概念を説明するのに役立つと考えました。

バランスシートのアナロジーとして説明する技術的負債


上のバランスシートで「ソフトウェアとしての価値」の一部として組み込まれているように、「技術的負債」は必ずしも絶対悪ではないということは理解しておかなければいけません。

われわれが「技術的負債」と呼んでいるものも、READYFORの歴代エンジニアたちがその時々でベストを尽くした汗と涙の結晶なので、敬意と感謝の念を持って対処していきたいと思っています。

技術的負債は絶対悪ではない


大事なのは「技術的負債」「技術的純資産」の特性を理解することです。

特性を理解するのが大事


「技術的負債」に比べて「技術的純資産」が多い場合、最初に生み出すソフトウェアの価値は比較的小さくなりますが、時間軸に沿っての成長のスピードは大きくなります。

技術的純資産が多い場合の成長速度


対して、「技術的純資産」に比べて「技術的負債」が多い場合には、初期に生み出す価値は大きくすることが可能ですが、時間軸に沿っての成長スピードは逓減していってしまいます。

技術的負債が多い場合の成長速度


では、技術的負債が貯まってしまった場合には一体どうすれば良いのでしょうか。

どうすればよいのか


そこで、リファクタリングという概念が登場します。

リファクタリングという概念


リファクタリングは、「ソフトウェアの価値」を変化させることなく、「技術的負債」を返済して「技術的純資産」に変換することに例えることができます。これによって、その後の開発スピードに加速をつけることができます。

リファクタリングという概念の説明


つまり、今後のスピーディーな成長を支えるためにも、リファクタリングは非常に重要な戦略の一つとなっていきます。

READYFORでは複雑なドメインを扱うため、ドメインエキスパートとの対話を大切にする ドメイン駆動設計 をリファクタリングの軸に添えたいと思っています。

リファクタリングの軸に添えるのはドメイン駆動設計


さて、READYFORでは非エンジニアがBPMNのモデリングツールを駆使して業務ワークフローを可視化するなど、エンジニアとドメインエキスパートが対話できる土壌は育っています。

ドメインエキスパートと対話できる土壌は育っている


あとは、一緒に推し進めていく仲間が必要です。

仲間が必要


このセッションでは、戦術的設計や実装など、詳細の話はしませんでした。

詳細の話はしませんでした


なぜなら、当日セッションを聴いている方に、そして今このブログを読んでいる あなた に事例をつくっていっていただきたいから。

あなたに事例をつくっていただきたい


ということで、READYFORでは複雑なドメインの再設計とリファクタリングを一緒に推し進めてくれる仲間を大々々募集しています。

仲間を大募集しています


という話をしてきました🤗

楽しんでいただけたら嬉しいです。


セッションでもお伝えしたように、READYFORでは各種ポジションで エンジニア大募集中 なので、興味を持った方はぜひご応募ください。

新しいお金の流れを作る、リードバックエンドエンジニア募集! - READYFOR株式会社のWebエンジニアの求人 - Wantedly

新たな資金流通エコシステムの基盤をつくる、決済・会計エンジニア募集! - READYFOR株式会社のWebエンジニアの求人 - Wantedly

資金調達の新たなスタンダード、READYFORフロントエンドエンジニア募集 - READYFOR株式会社のWebエンジニアの求人 - Wantedly

急成長中のベンチャーで品質管理をお任せする、一人目のQAエンジニア募集! - READYFOR株式会社のWebエンジニアの求人 - Wantedly

スライドはこちら

当日のセッションの様子はこちらのTogetterにまとめられています。

togetter.com


Object-Oriented Conferenceは、最初から最後まで非常に興味深いセッションが目白押しで、非常に密度の濃いイベントでした。運営の皆さま、登壇者の皆さま、素敵な1日を本当にありがとうございました!

READYFORメンバー

2/6(水) 開催「CTOナイト#1 気鋭のスタートアップ4社に学ぶ、エンジニア採用と組織作り」に登壇しました!

こんにちは。READYFORです。

先週2月6日に開催された、『第1回 CTOナイト 気鋭のスタートアップ4社に学ぶ「エンジニア採用」と「組織作り」』にREADYFOR VPoE 伊藤博志 (@itohiro73)が登壇しました!

CTOナイトは、KEPPLE ACADEMYが主催しており、スタートアップ4社のCTO・VPoE・CIOが登壇し、各社の組織作りにおける特徴やぶち当たった壁、それを乗り越えるべくどのように取り組んでいるかなど、今、現場で起きている事象をお話するイベントです。




f:id:readyfor:20200213091317j:plain
*写真中央が伊藤です

登壇した感想を聞いてみると……?

@itohiro73 : 今回クローズドなイベントだったため、現在のREADYFORのビジネスのフェーズ感や、エンジニア組織として抱えている課題やそれらへの対処の施策など、かなりざっくばらんに話させていただきました。とくに、SpotifyのSquadモデルに沿ったチーム組成をし始めている取り組みに関しては皆さん興味を持っていただいたようで、多くの質問が投げかけられてとても盛り上がりました。他社さんの事例もフェーズ感や業種、規模感による課題がそれぞれ違って私としても非常に興味深く聴くことができました!


f:id:readyfor:20200213095438p:plain
※左から for StartupsのCTO・戸村氏、READYFORのVPoE・伊藤氏、HandiiのCTO・森氏、UNIVRSのCIO・藤川氏、ケップルアカデミー・藤原氏



さて、READYFOR VPoE 伊藤博志 @itohiro73 は、今週末の2月16日に開催されるOOC(Object Oriented Conference)にも登壇します! ooc.dev

【Object-Oriented Conference 2020とは?】

オブジェクト指向をテーマに情報を共有したり、セッションを聴講することで参加者の知見を深めるためのイベントです。オブジェクト指向といっても、分析設計から、現場で活かすためのプラクティスなど様々なテーマがあります。伊藤が登壇するランチセッションでは、READYFORが抱えている技術的課題と、それらをどう解決しようとしているかをお話しする予定です。

▼セッション詳細

テーマ「READYFORにおける複雑なドメインとレガシーシステムとの戦い方」

日時:13:30〜 場所: お茶の水女子大学 (共通講義棟 2-201 )

ぜひともお楽しみに!

READYFOR の「テックブログ開設」までの軌跡

READYFOR の CTO をしている町野です。記念すべき READYFOR Tech Blog の初回担当を拝命しました。

私たちは、クラウドファンディングサービス「READYFOR(レディーフォー)」の開発、運営をしています。クラウドファンディング (Crowdfunding) とは、インターネットを通じて多くの方々から資金調達(ファンドレイジング)をするための仕組みです。社会貢献活動資金から研究開発資金、事業立ち上げ資金まで、様々な資金需要を支えるプラットフォームとなっています。

readyfor.jp

READYFOR は、2011年3月にローンチした国内初のクラウドファンディングサービスで、スタートアップ企業としては長いことやっている部類に入るのですが、「どんな技術でどんなプロダクトをつくっているか」ということはあまり知られていないんじゃないかと思います。私(町野)自身、参画するまでは READYFOR に対して「テクノロジー」のイメージは持てていませんでした。

実際、エンジニアが人数的にも割合的にも少ない期間が長く、対外的に技術発信をする余裕も文化もなかったのですが、今やメンバーから自発的に「我々もテックブログを早く始めたい!(から、CTO は早く1記事目を書け!)」という強い声が上がるほどに、どんどんエンジニアリング組織として強くなってきています。とってもうれしいので、「テックブログ開設」という今日のよき日に至る、この1年の取り組みを簡単に紹介させてください。

CTO としての初期ミッション

ずっとスタートアップ業界に身をおいていた自分は、「想いが乗ったお金を流れを増やす」 という READYFOR のミッションに強く共感して、2019年1月に CTO としてジョインしました(当時 CTO ポジションは存在せず)。

https://blog.readyfor.jp/n/n23035223aee1blog.readyfor.jp

その頃は、2011年から拡張され続け大きなモノリスとなった Rails アプリケーションを数人のエンジニアでどうにか維持している状況で、技術的にはお世辞にも「イケてる会社」ではなかったのですが、逆をいえばテクノロジーによる伸び代がメチャクチャ残っている訳で、この会社で技術経営を担ったら絶対おもしろいなと思いました。

入社直後に行った経営合宿では「10年後の READYFOR」というワクワクする大きな未来を夜通し語らいつつも、最初の経営会議で共有した「CTO の初期ミッション」は以下のようなものでした(原文ママ)。

## 初期ミッション:基礎固め

【READYFOR をテックカンパニー化することで、既存事業を加速させ、新規事業に素早く挑戦できる組織およびシステムの基礎を構築する】

*   テックカンパニー化
    *   テクノロジーの力によって事業全体がブーストされている状態
    *   全社的な取り組みであり、エンジニア部門に限るものではない
*   既存事業を加速
    *   マンパワーに律速されない、プロダクト自体の強化
    *   継続的改善を行うためのシステム/ワークフローの構築
*   新規事業に素早く挑戦
    *   不確実性の高い事柄に対し素早い意思決定ができる状態
    *   素早い仮説検証が可能なプロジェクト体制の構築
*   組織およびシステムの基礎
    *   上記を実現するための組織再編
    *   上記を実現するためのシステム再構築

## 2019年1月のアクション

*   ヒアリングの実施
    *   事業/組織の現状を複数視点から把握する
    *   エンジニアチームに限らず全部門の話を聴く
    *   組織に根付いている価値観の把握
    *   業務における強みや課題の把握
*   テックビジョンの共有
    *   テックカンパニー化する意義を社内全体と共有
    *   スタートアップとして求められる成長、俊敏さ
    *   お金を預かる事業者として求められる信頼、慎重さ
    *   どうした価値観と体制によってそれらを実現していくか
*   社内情報体制の整備/周知
    *   社内情報を効率的に整理し、必要な情報を Pull できる状態
    *   オープンコミュニケーションの徹底(透明性)
    *   誰もが気軽に情報発信できる組織文化(心理的安全)
    *   お金を扱う企業としての情報セキュリティ体制(社会的責任)

## 2019年1~3月のアクション

*   組織再編案の策定
    *   セクショナリズムを防ぐ体制にする
    *   職種で役割を縦割りしないプロジェクト体制
*   プロダクト部門の再定義
    *   Product Manager / Project Manager / Scrum Master / Engineer / Designer
    *   各々が自分の役割/責任範囲を認識する
*   目標管理制度の整理
    *   OKR の意義の周知と運用方法の改善
    *   1on1 を通じ、会社側と社員側のキャリアパスをイメージを揃える
*   採用戦略/ポリシーの策定
    *   今取るべき人材の定義、採用戦略
    *   採用基準として全社的に大切にするべき価値観
*   システム再構築の方針決め
    *   単発的な随時タスクを全体の○○%以下に抑える
    *   既存システムのリファクタリング/新システム基盤の設計


「今後、大きなことに挑戦していくためにも、まずはバケツの穴を塞ごう。」

そんな話を(エンジニアは数%しかいない)全社ミーティングで話しつつ、既に進んでいた新規機能開発をストップし、社内受託開発のようになっていた開発体制を見直し、エンジニアが主体的にプロダクト開発に関わる体制にしていきました。

採用、採用、採用!

「基礎固め」の次のフェーズでは、とにかく採用に多くの時間を使っていました。組織づくりにおいて、最初にどんな人が旗を振るかはとても重要です。単純にエンジニアリソースも足りませんでしたが、なによりもまず、一緒に組織をつくっていけるメンバーが必要でした。

「技術力だけでなく組織視点も持ち合わせ、他部門にリスペクトを持ち、力強く自走できるメンバーじゃないとダメ!」と、採用担当者を困らせつつも、妥協しない採用活動を粘り強く続けていました。

その結果、VPoE として入った id:itohiro73 をはじめ、素晴らしいメンバーがどんどんジョインしてくれました。Engineering Manager, Backend Engineer, SRE, Corporate Engineer, Product Designer, etc. 各領域の専門性を持ちつつも、みな「良い組織をつくりたい」という想いの強いメンバーです。

https://blog.readyfor.jp/n/n05c0a6b1a595blog.readyfor.jp

(ちなみに、まだまだ絶賛採用中なので、興味ある方はぜひご一報を)

https://www.wantedly.com/projects/407089www.wantedly.com

「乳化」が進む READYFOR のエンジニアリング組織

READYFOR では、よく「エンジニアの乳化」という言葉を使います。卵を入れると水と油が混ざり合ってマヨネーズが作れるようになる、あの「乳化(にゅうか)」です。

私たちが「テックカンパニー化」というとき、それは「エンジニア/非エンジニア」と職種で線引きして単純にエンジニアの数を増やすことでは決してなく、エンジニアリングが組織全体に広がっている状態になることです。

クラウドファンディングのプラットフォームとして様々な種類のお金の流れを扱う READYFOR では、プロジェクト審査や支援金の会計処理など、多くの業務オペレーションがシステムと密接に繋がっています。それを支えるためにはエンジニアが各組織部門に乳化していくことがとても重要で、それによってオペレーションの卓越性が高まっています。

おわりに

そんな READYFOR のエンジニアリングチームが開設したテックブログ、今後の記事をお楽しみに!


就活ではよく「潤滑油のような人」という言葉が使われるそうですが、弊社は「乳化剤のような人」を募集中です。

https://www.wantedly.com/projects/414299www.wantedly.com

https://www.wantedly.com/projects/414310www.wantedly.com