くらしのマーケット開発ブログ

「くらしのマーケット」を運営する、みんなのマーケット株式会社のテックブログ。積極採用中です。

くらしのマーケット開発職向けの会社紹介資料を公開します!

みんなのマーケット 開発職向け 会社紹介資料を公開します

こんにちは。みんなのマーケットでCTOをしている戸澤です。

みんなのマーケットでは採用を強化しており、 2020年11月から2021年2月の4ヶ月間で、開発メンバーだけでも18名が入社しています。

カジュアル面談や面接をしてきた中で、「当社が何を考えていて」、「今どんな状態で」、「これから何をするのか」が候補者に知られていないことに気が付きました。

そこでカジュアル面談や面接の中でお話している内容に加え、技術やプロダクト、働き方などの5つの項目をスライドにまとめて、公開します!

主な内容

  • くらしのマーケット について
  • 開発体制と技術スタック
  • プロダクトでこれから目指すもの
  • フルリモートワークでの働き方
  • 評価制度と報酬

内容はくらしのマーケットの開発職であるエンジニア、プロダクトマネージャー(PM)、UI/UXデザイナー、QAに特化しています。

このスライドは今後も定期的に加筆、更新していく予定です。

会社紹介資料

全職種で積極採用中!

ご興味のある方は以下リンクより応募ください。カジュアル面談も歓迎です。 https://www.minma.jp/recruit

全員で会議できる時間をいもす法で探そう

こんにちは。SRE / バックエンドエンジニアのマノメです。

前回の記事 を読んで、以前私が思いつきで作った、「全員で会議できる時間はいつか?」を調べるコードを書いたことを思い出しました。
どういうものかというと、チームメンバーの数日間の出勤記録をもとに全員が揃っている時間を割り出す、という至ってシンプルなものです。

弊社では現在、コアタイムなしのフレックスタイム制で、多くのメンバーがフルリモート出勤です。
会議をしたい!となったらもちろん、開始時間を決めてその時間に出勤するようにするべきなのですが、とはいえ生活時間を急に変えるというのは朝が弱い私のような人間にとってはなかなか大変です。
なので、チームメンバーが全員揃う時間帯を割り出して会議を設置すれば、そういった杞憂をせず済むと考えたわけです。
特にチームの再編を行った際は、このデータが参考になるのではないでしょうか。
そういった私の思いつきでコードを書いたものの、そのときにはすでにチームができて数ヶ月経って会議時間も決まっていたため、誰にも披露することなくお蔵入りになりました。

今回は、このとき作ったコードを元に、累積和のアルゴリズムのことをちょっとだけ話そうと思います。

作ったもの

Go で書いています。
余談ですが、くらしのマーケットでは一部で Go が使われている箇所があります。

用意したデータ

A 〜 D の 4 人の出勤記録をテキストに書き起こします。
※記事のために適当な値を作っています

# A
08:54-17:24
09:42-17:37
09:39-18:24
10:46-19:33
# B
10:23-20:32
10:16-18:28
10:28-19:42
10:45-19:36
# C
10:08-18:32
10:07-19:48
10:00-19:49
10:11-19:27
# D
11:14-21:00
11:02-20:47
11:47-21:19
10:59-21:04

書いたコード

func main() {
    // データを読み込んでいい感じにする
    // [[As_start_time, As_end_time], [Bs_start_time, Bs_end_time], ...]
    input := read()

    data := make([]int, 60*24)
    for _, i := range input {
        // i[0] が 出勤時間, i[1] が 退勤時間
        data[i[0]] += 1
        data[i[1]] -= 1
    }

    // 必ず全員いる時間 = データの数
    max := len(input)

    // 全員いる時間を探す
    cur := 0
    isMax := false
    start, end := 0, 0
    for index, d := range data {
        cur += d
        // 全員が揃った時間の記録
        if !isMax && cur == max {
            start = index
            isMax = true
        }
        // 全員が揃っていた最後の時間の記録
        if isMax && cur == max-1 {
            end = index - 1
            isMax = false
        }
    }

    fmt.Printf("%d:%d - %d:%d\n", start/60, start%60, end/60, end%60)
}

結果

与えられたデータより、11:47 - 17:23 が適切な会議の設定時間となります。

解説

さて、アルゴリズムについての話ですが、今回使ったのは いもす法 という素晴らしいアルゴリズムです。
これは、累積和を用いて複数の要素の重なりや深さなどを計算するものです。

例えば以下のような出勤表があるとします。

f:id:curama-tech:20210122132636p:plain
出勤時間のグラフ

これをもとに、愚直に累積和のデータを作るならこうなるでしょう。

08:00 09:00 10:00 11:00 ~ 17:00 18:00 19:00
A 0 0 1 1 1 1 1
B 0 1 1 1 1 0 0
C 0 0 0 1 1 1 0
合計 0 1 2 3 3 2 1

この「合計」の配列を用意して計算することになります。
ただ、プロットするのに以下のような処理が必要です。

input := read()
data := make([]int, 60*24)

// データのプロット
for _, i := range input {
    // i[0] が 出勤時間, i[1] が 退勤時間
    // 1 つのデータに対して、該当範囲を"塗りつぶす"イメージ
    for k := i[0]; k < i[1]; k++ {
        data[k]++
    }
}

max := len(input)

// シミュレート
start, end := 0, 0
isMax := false
for index, d := range data {
    // 全員が揃った時間の記録
    if !isMax && d == max {
        start = index
        isMax = true
    }
    // 全員が揃っていた最後の時間の記録
    if isMax && d == max-1 {
        end = index - 1
        isMax = false
    }
}

これは、人数(N) と 時間範囲(T) に対して、データのプロットに必要な計算量は O(N*T) 、シミュレートに必要な計算量は O(T) となり、合計で O(N*T + T) となります。

さて、いもす法を用いると、かなりシンプルに、計算量も抑えられます。
データの作り方が肝で、「出勤したら+1、退勤したら-1 する」という方法を取ります。

08:00 09:00 10:00 11:00 ~ 18:00 19:00 20:00
A 0 0 +1 0 0 0 -1
B 0 +1 0 0 0 -1 0
C 0 0 0 +1 0 -1 0

よって、データのプロットは最初に書いたコードの通り、

for _, i := range input {
    // i[0] が 出勤時間, i[1] が 退勤時間
    data[i[0]] += 1
    data[i[1]] -= 1
}

となります。
この場合、データのプロットに必要な計算量は O(N) 、シミュレートに必要な計算量は O(T) となり、合計で O(N+T) となります。
処理がシンプルになり、計算量もかなり減ります。

これなら、人数が大幅に増えても計算量が大きくなりすぎないですね。

さいごに

結局、いもす法を使って作った「全員で会議できる時間を探す」というコード自体は、実用性があるのかないのかよくわからない結果になりましたが、いもす法は実際のデータ分析においてとても役に立つと思います。
例えばこのご時世ですから、部屋の中に一定以上の人数がいる時間帯を調べて換気の強さを調整するというのができそうですね。
くらしのマーケットでいうなら、登録している出店者のサービス提供が最も盛んな時間帯を調べたい、といった場面で役に立つかもしれません。

こういったアルゴリズムは知っているとひょんなことで役に立つかもしれないので、そういった知識を深める場として競技プログラミングはいい機会だと思います。
競技に参加しなくても、エクササイズとして過去問に取り組むだけで勉強になると思います。
ぜひ、挑戦してみてください!

競技プログラミングのススメ

こんにちは、 @akira です。本年もよろしくお願いいたします。

2021 年のテックブログ一本目は、競技プログラミングの紹介記事になります。

サンプルコードは Go で記載しています。

競技プログラミングとは

出題されたお題をデータ構造とアルゴリズム(+数学 etc...)を駆使して解く競技です。

実際のコンテストでは制限時間内に難易度の違う問題が複数出題されるので、それらをいかに早く解くかを競います。

例えばこんな問題が出題されます。

自然数 n (1 <= n <= 1000)が与えられたとき、1からnまでの和を求める calcSum() を実装せよ

まず naive に brute force でこの問題のアルゴリズムを実装してみましょう。

brute force は、パスワードを一文字ずつ変えながらログインを試みる攻撃手法 brute force attack の名前などに使われており、「強引に何かを行う」といった意味をもつ単語です。

競技プログラミングにおいては、「総当りで計算する」といった意味合いがあります。

func calcSum(n int) int {
    rev := 0
    for i := 1; i <= n; i++ {
        rev += i
    }
    return rev
}

このとき、時間計算量は O(n) 、空間計算量は O(1) です。

時間計算量は、ざっくり言うと必要な手順の回数を指します。上記のアルゴリズムでは n 回ループが実行されるので、O(オーダー)記法で O(n) になります。

空間計算量は、ざっくり言うと必要なメモリの量を指します。上記のアルゴリズムでは、返り値の変数 rev 以外はメモリを使っていないとみなすと、O(1)(常に一定)と表せます。

この問題、時間計算量 O(1) で解くことができます。

問題は 1~n までの和を求めているので、初項 1、公差 1 の等差数列の和を求めればよいことになります。

初項 a、公差 d、項数 n、末項 l の等差数列における初項から第 n 項までの和 S は、以下の式で求められます。

S = n * (a + l) / 2 =  n / 2 * (2 * a + (n - 1) * d)

今回は a = 1, d = 1, n = n, l = n であるため、上記に代入すると

S = n / 2 * (2 * 1 + (n - 1) * 1) = n * (n + 1) / 2

この公式を利用することで空間計算量は O(1) 、今回のように n が大きくない(n <= 1000) 場合は、時間計算量 O(1) で計算することができます。

func calcSum(n int) int {
    return n * (n + 1) / 2
}

競技プログラミングの楽しさ

上記の問題だけでは少し物足りなかったかもしれません。

もっと本格的な問題を考えてみましょう。

ローマ数字は I, V, X, L, C, D, M (それぞれ 1, 5, 10, 50, 100, 500, 1000)を組み合わせて数を表す
通常は左から右に向かって大きい数から順に表すが、以下のケースは例外となる

・I は V(5), X(10) の前に書くことで IV(4), IX(9) を表せる
・X は L(50), C(100) の前に書くことで XL(40), XC(90) を表せる
・C は D(500), M(1000) の前に書くことで CD(400), CM(900) を表せる

自然数 num (1 <= num <= 3999) が与えられたとき、そのローマ数字を文字列で返す convertToRoman() を実装せよ

私は最近この問題を解いたのですが、最初の回答が以下です(ワントゥスリィ!)

var m map[int]string = nil

func convertToRoman(num int) string {
    m = make(map[int]string, 0)
    m[1] = "I"
    m[2] = "II"
    m[3] = "III"
    m[4] = "IV"
    m[5] = "V"
    m[6] = "VI"
    m[7] = "VII"
    m[8] = "VIII"
    m[9] = "IX"
    m[10] = "X"
    m[20] = "XX"
    m[30] = "XXX"
    m[40] = "XL"
    m[50] = "L"
    m[60] = "LX"
    m[70] = "LXX"
    m[80] = "LXXX"
    m[90] = "XC"
    m[100] = "C"
    m[200] = "CC"
    m[300] = "CCC"
    m[400] = "CD"
    m[500] = "D"
    m[600] = "DC"
    m[700] = "DCC"
    m[800] = "DCCC"
    m[900] = "CM"
    m[1000] = "M"

    rev := ""
    for num >= 1000 {
        q := num / 1000
        num %= 1000
        rev += strings.Repeat(m[1000], q)
    }
    num, rev = calc(rev, num, 100)
    num, rev = calc(rev, num, 10)
    _, rev = calc(rev, num, 1)
    return rev
}

func calc(rev string, num, d int) (int, string) {
    q := num / d
    num %= d
    rev += m[q * d]
    return num, rev
}

ゴリ押し感満載で、前半のローマ数字を打ち間違えたらそれだけで不正解となりそうなコードですね。実装も大変だった記憶があります。

ただ、上記のコードでも正解として通過はしました。

後ほど比較するためにざっくりで時間計算量を出すと、

  • num を 1000 以下にするのに for で記載してますが、1000 で modulo を取っているのでループは1回しか回らず
  • strings.Repeat() は O(log2(q)) とすると

最終的には O(log2(q)) でしょうか。

このコードをより改善しようと試みて書いたのが次のコードです。

var m map[int]string = nil

func convertToRoman(num int) string {
    m = make(map[int]string, 0)
    m[1] = "I"
    m[5] = "V"
    m[10] = "X"
    m[50] = "L"
    m[100] = "C"
    m[500] = "D"
    m[1000] = "M"

    rev := ""
    for num >= 1000 {
        q := num / 1000
        num %= 1000
        rev += strings.Repeat(m[1000], q)
    }
    num, rev = calc(rev, num, 100)
    num, rev = calc(rev, num, 10)
    _, rev = calc(rev, num, 1)
    return rev
}

func calc(rev string, num, d int) (int, string) {
    q := num / d
    num %= d

    if q == 9 || q == 4 {
        rev += m[d] + m[(q+1) * d]
    } else if 6 <= q && q <= 8 { // 8,7,6
        rev += m[5 * d] + strings.Repeat(m[d], q % 5)
    } else if 2 <= q && q <= 3 { // 3,2
        rev += strings.Repeat(m[d], q)
    } else if q == 5 || q == 1 {
        rev += m[q * d]
    }

    return num, rev
}

より短い行数で書けましたが、桁に 6,7,8 が登場する場合は strings.Repeat() も呼ばれるため、時間計算量は先程のものから悪化してしまっています。

どうにかならないものかと、他の方が提出した回答を眺めていると、次のような考え方で実装されていて驚愕でした(別の言語だったため、Go で再実装しています)。

今回の問題の numnum <= 3999 の制約があります。つまり千の位はたかだか 3 までということです。そこから次のような考え方が生まれたのでしょう。

func convertToRoman(num int) string {
    M := []string{"", "M", "MM", "MMM"}
    C := []string{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}
    X := []string{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}
    I := []string{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}
    return M[num/1000] + C[(num%1000)/100] + X[(num%100)/10] + I[num%10]
}

各桁で取りうる値を全て slice に保持しておいて、後はその値の文字列を連結しているだけの非常にエレガントなコードです。

時間計算量は、slice (array) は memory access のため O(1) 、 num <= 3999 であることと定数であれば O(1) としてみなせるため O(1 * 4) = O(1) になります。

こんなコードを最初にかけたら非常にスマートで楽しいに違いない、と苦しみながら解いた私は感じます。

これが競技プログラミングの楽しさではないでしょうか。

オススメの競技プログラミングサイト

以下のサイトが個人的におすすめです。無料で問題を沢山解けます。

上記以外にも、ゲーム感覚で挑戦できるCodingameなど、たくさんあります。

自分に合ったプラットフォームを選択するとより競技プログラミングが楽しくなるかなと思います。

終わりに

競技プログラミングに取り組むことで時間計算量や空間計算量を意識するようになり、実務でコードを書く際にも効率的にリソースを使えるようになります。

上記のような一見大変そうな問題をスマートに解くことにも楽しさはあるので、まだご経験のない方はこれから挑戦してみてはいかがでしょうか。

それでは!

2020年のQAチームを振り返る

こんにちは、QAエンジニアのざきです。 イルミネーションにワクワクする時期ですが、今年は大人しくStay Homeを続けています。

f:id:curama-tech:20201224104953j:plain
数年前の大根やぐらライトアップ〜宮崎市田野町〜

2020年も年末を控え、来年の行動目標やチーム方針を検討する中で、そう言えば今年のQAチームはどうだったのか、簡単に振り返りたいと思います。

▼QAチーム体制

2020年1月よりQAチームとして独立したチーム体制になりました。当時のメンバーは私を含めて2名。 (昨年時点では複数ある開発チームの中の1チームにQA2名が所属していました)
11月に2名がジョインし、以降は4名体制になりました。※フルタイム勤務のメンバーだと3名体制。

▼仕事の内容

各所からの依頼を受けて大まかに以下の作業を行っています。

【開発チーム関連】

  • テスト計画の作成

  • テスト設計・レビュー

  • テスト実施(結合テスト[IT]、総合テスト[ST])

  • リリース判定

【その他】

  • 不具合の報告 >調査・切り分け >解決 or 修正依頼

  • 仕様問い合わせ >回答

  • データ修正依頼 >担当チームへの仲介 >実行結果の確認

▼今年変わったこと

フルリモート化

会社として、チームとして、大きく変わった点としては「働き方」です。2020年12月時点でQAメンバーは全員が「ジョブ型コース(完全リモートワーク)」を選択しています。
コミュニケーションツールはSlack、Zoomがメインとなり、直接顔を見て話す機会は無くなりましたが仕事はこなせています。

また、新メンバーのオンボーディングも、フルリモート対応でありながら成功しています。
気を付けた点として、分からないことや説明しづらいものは、即座にZoomを繋げて対面的な説明を行った事です。 もちろん、内容によりますがテキストベースで解決出来るものはSlackで返答を行い解決します。

しかし、モバイル端末の操作・挙動やブラウザで発生している事象についてとなると、テキストベースで話を進める事は非効率(認識がずれていると後々手戻り・やり直しになる)になるため、即解決!をモットーに即Zoom!で対応しました。 後のお話で、オンラインでも顔を見て話をしてもらえると安心感が高まり、状況を落ち着いて整理・説明できた、と嬉しいコメントをいただきました。

タスク・スケジュールの可視化

昨年は開発チームのメンバーとして所属していたため、タスク一覧や管理シートはなく、個人のタスクは日々のデイリーで報告するのみで、パッと見てアサイン状況や進捗度合いを確認する術はなく、都度聞いて確認するというスタイルでした。

独立したチームとなりメンバーの状況が分からない(相手から見れば私の状況が分からない)ことは、思った以上に影響があり、例えばQA宛に依頼されたタスクを互いに対応しているなど、情報共有と業務連携で改善が必要だと気付きました。

即座に、Googleスプレッドシートを利用して、タスクのアサイン・対応状況を一覧化し、先々のリリース予定も把握できるようQAカレンダーを作成・運用しました。これにより、重複対応が発生することなく、期限と進捗を見て必要時にはヘルプに入るなど、互いの状況が把握しやすく連携も取りやすい状態へ進化する事ができました。
また、このシートは誰でも閲覧可能なため、QAのリソースやスケジュールの見通しを全体的に公開できる良いキッカケにもなりました。

▼今年の課題と来年への思い

QAチーム発足から1年を前に、率直な課題として以下が挙げられます。

1.経験値・ナレッジの属人化

開発チームの数に対してQAメンバーの人数が少ないため、QAはいくつかのプロジェクトを兼任しなければなりません。そうなるとどうしても、「そのメンバーしか把握していない仕様やテスト作業のナレッジ」が発生します。細かな粒度でアップデートされる情報類についても同じ事が言えます。

新メンバーも含め、チームメンバー全員が一定の水準でテスト作業を行えないとQA(品質保証)にはなりません。限られたリソース・定められた期限の中でどの様にチームとして解決すべきか皆で一緒に取り組みたいと思っています。

2.テスト自動化

これは主に、リグレッションテストの効率化を図りたいと考えています。デプロイ前に実行する自動テスト(E2E)は開発エンジニアにて作成されていますが、QAの為のテスト自動化は実現できていません。リリースの大小を問わず、毎回行う繰り返しテストを手作業で確認するのは確実性はありますが、効率化できるポイントでもあると思います。どんなタイミングでも遅延することなくスムーズなリリースを提供するためにも腹を決めてやるしかないのです。

とは言ったものの、、テストシナリオの策定、コードの記述、動作確認・メンテナンスなど、テスト自動化は実現したから終わるものではなく、半永久的に付き合っていく事になります。と同時に、実行結果の取得についても、単純にエラーが無かったなどの判断ではなく、デザインやボタンの状態も確認する必要があるなど、考える材料が多くなかなか踏み出せていませんが、メンバーも徐々に増えているので来年こそは取り組もうと考えています。(皆様お力添えくださいませ)

3.ボトルネックの汚名返上

前項1.で取り上げたように、QAはいくつかのプロジェクトを兼任しているため、リリースタイミングが重複すると進捗度合いや作業量によってリソース不足に陥ります。そういう時は開発チームにヘルプいただく事になりますが、これにより、ヘルプしてもらう方の本来の業務をストップさせてしまいます。と同時に、それでもテストが間に合わずリリースが遅延するとなればQAがリリースのボトルネックになってしまいます。

2020年(2名体制の頃)の苦い思いを繰り返さないよう、2021年は増強されたチームで汚名返上をします。まずはしっかりとしたテスト計画を立てること、リリース時期が重複する際のリソース配分・割当をカレンダー管理した上で、どうしても調整が必要な時にはチーム内で協議した結果を開発チームへ共有し全員で解決策を見出す、これらを徹底します。爆速で進むくらマの進化を速やかにユーザーへ届けるためにQAも進化し続けます。

おわりに

チームビルディングについては手探りな領域が多いものの、チーム内外問わず、全社的に「やってみよう!」という前向きな雰囲気なので、まだまだやれる事はある!と感じています。何をするのか・しないのか、ではなく「何が出来るかな」を最初に考えながら来年も様々なミッションを全員でクリアしていきます。

来年もQAに関する情報を発信していくので、どうぞお楽しみに!

フルリモートワークでのオンボーディング施策

こんにちは。みんなのマーケットでCTOをしている戸澤です。

当社ではコロナ以前からリモートワークで働ける状態でした。 ただどちらかというと東京もしくは宮崎のオフィスで働くのが主流で、利用するメンバーはそこまでいませんでした。

3月下旬のリモートワークを会社全体で初めるタイミングでは、うまく仕事が回るのだろうか、という不安がありましたが、試行錯誤していく中でリモート環境下でも開発を回していく体制や仕組みを整えられてきました。 その結果、オフィスへの出社が不要なフルリモートでの採用も開始し、募集も日本全国、全世界に拡大しました。 その成果もあり、従来のオフィス出社の前提だと採用できなかったであろう鹿児島や韓国に住んでいるメンバーも入社しています。

今回はフルリモート環境下で入社したメンバーのオンボーディングをどう進めているかについて振り返っていきます。 フルリモートワーク以前から在籍しているメンバーはメンバー間の関係性や業務の基礎理解がすでに出来ている状態ですが、新しく入社するメンバーはそれがない状態で、直接会わずにリモートで進めるのは初めての試みでした。

昨日(2020/12/17)の東京の感染者は過去最多822人となりましたが、フルリモートでの転職を考えている方が働くに際しての安心できる材料として、また、フルリモートに悩んでいる組織運営者の助けとなれれば幸いです。

新卒入社メンバーに行ったこと

他メンバーが隣に座っている状態を再現する

新卒メンバーは4月1日の入社日からリモートでの研修、OJTとなりました。 まだ社会人としての働き方に慣れてない状態、業務の基礎がつかめてない状態で自宅にひとりになるフルリモートは懸念がありました。

研修は例年通り新卒向けのオンボーディング用のドキュメントに沿って進めますがリモートの状況だと、わからないところで手が止まってしまったり、新卒メンバーの会話の中で理解を深めることが難しい状況でした。

その対策として、新卒メンバーと指導メンバーでZoomを繋ぎっぱなしにしました。このZoomはいつもはミュートにしておきますが、ミュートを解除して話しかけると誰かが反応できる状態になります。これにより、新卒メンバー同士での解決や、新卒メンバーの疑問をすぐに指導メンバーに確認し解決することや、相談しやすい状況を作ることができました。

特に新卒メンバーのオンボーディングでありがちな、会話の中で確認を取っていくためテキストで表現が難しい内容や、遠慮して聞きづらいという状況を回避できました。 この施策は4月から8月まで行い、Zoom以外のビデオ通話サービスも試しましたが、ミーティングを開きっぱなしにしやすいことや、通話の品質や安定性でZoomが一番使いやすかったです。

中途入社メンバーに行ったこと

他メンバーが隣に座っている状態を再現する

中途メンバーは社会人として仕事を進められるためZoom繋ぎっぱなし施策は行っていませんが、次に施策を行っています。

  • ペアプログラミング
  • Slackにチームスレッドをつくり気軽に聞けるようにすること
  • Slackのテキストだと伝えづらいものはカジュアルにZoomやGoogle Meetを使い会話して解決すること
  • チューター制度
  • デイリーMTGの中で困っていることも話してもらい、早くに他メンバーがサポートに入れる状態を作ること

また、業務やスキル面以外でお互いにどんな人と働くか知りたいという意見もリモートワークを進めていく中で上がってきました。その方法として、全チームではありませんが、Zoomランチや、海外出身のメンバーも多いので出身の国について語ってもらう疑似海外旅行Zoomなどを開催することもあります。

内容の抜け漏れをなくす、検索できるようにする

4月以降、ドキュメントのカバレッジを上げていく中で、オンボーディング用のドキュメントの充実と更新を進めています。

オンボーディング用のドキュメントができる以前は、会話の中で教えていくことが多く、質問されないと伝え漏れること、時間がかかること、伝え間違えることがありました。そのため、開発していく中でのミスや認識違いによる手戻りが発生したほか、特にフルリモート下で組織を拡大していくに当たって、そのスケーラビリティが課題となっていました。

その対策として、開発フローやルール、システム、プロダクトの理解ができるオンボーディング用のドキュメントをエンジニア、デザイナー、QAの職種別に作成しました。作成後も入社のタイミングで不足している内容や変更になっている部分のアップデートも継続的に行っています。

その成果として、1回の入社人数が増えても対応出来ています。 また、部署配属から概ね1週間ほどで業務に取り掛かることができるようになり、事前の理解度が高まっていることや自分で調べることができる状態にもなっているため、進捗が途中で止まることが少なくなりました。

最後に

転職、就職しようとしている方は入社先で活躍できるか、心配されると思います。

その心配を解消でき早く活躍、成果をあげられるよう、これからもオンボーディングのハードルを下げ、新しいメンバーが業務やルールを早く理解できるように整備を続けていきたいと思います。