Chatbotを入れてちょっと改善した話

こんにちは、naoです(YOUTRUSTアカウントTwitterアカウント)!

最近新たな趣味として、バイクを始めました。

道の駅おばあちゃん市・山岡にツーリング

色々な場所へツーリングしたいと思っています😃


今回は、Chatbotを使ったちょっとした社内の改善について書きたいと思います。

何に困っていたのか

YOUTRUSTにも本番環境と同じ構成の、ステージング環境があります。(YOUTRUSTではSandbox環境という名前)

AWSのCodePipelineでデプロイする仕組みになっていて、ステージング環境にデプロイするには、特定のブランチに各メンバーが直接pushする形になっていました。 そのため 誰が使っているのか何がデプロイされているか がすぐに分からない状態でした。

開発メンバーが増えてきた為、 現在ステージング環境は使われているのか?何がデプロイされているのか? 等の情報を知りたいケースが増えてきて、都度Slackで全員にそのことを聞いたりする事が、ちょっと面倒だなぁという感じになっていました。

また、別ブランチへ間違えてpushしてしまうなどのケースも避けたかったので、変わりにpushしてデプロイしてくれるChatbotを作ることにしました。

作ったもの

主に欲しかったものとして、 誰がデプロイしたのか現在使用中なのかどうかだったので、これを満たすために以下の機能を作りました。

  • 最後にデプロイした人を保持しておく
  • 使用終了状態にできる
  • 使用状況を確認できる

今回は

あたりを使ってChatbotを作りました。

最後にデプロイした人を保持しておく

デプロイ時

yu-tora sandbox deploy [ブランチ名] でデプロイできるようにして、その時にユーザ名やブランチ名等を取得してDynamoDBに保存するようにします。

const { updateBranch, fetchCommit } = require('./github');

app.message(/^yu-tora sandbox deploy (.+)/ , async ({ context, say , message}) => {
  const branch = context.matches[1];

  const sha = await deploySandbox(branch);

  if (sha === null) {
    await say(`\`${branch}\` ブランチは存在しません`)
  } else {
    await say(`Sandbox環境に \`${displayBranchName(branch, sha)}\` ブランチをデプロイするトラ😼`);

    // SlackのユーザID、ブランチ名、SHAの値を保持する
    const params = {
      TableName: 'yu-tora',
      Key: {
        id: dynamoId
      },
      ExpressionAttributeNames: {
        '#s': 'slackUser',
        '#b': 'branch',
        '#h': 'sha'
      },
      ExpressionAttributeValues: {
        ':slackUser': message.user,
        ':branch': branch,
        ':sha': sha
      },
      UpdateExpression: 'SET #s = :slackUser, #b = :branch, #h = :sha'
    };
    await docClient.update(params).promise();
  }
});

const deploySandbox = async (branch) => {
  const commit = await fetchCommit(owner, repo, branch);

  if (commit === null) {
    return null;
  }
  const sha = commit.data.object.sha

  await updateBranch(owner, repo, sandboxDeployBranchName, sha, true);

  return sha;
};

使用終了状態にできる

使い終わった場合

yu-tora sandbox out でデプロイ時に保持しておいたユーザ名を消すようにしました。

app.message(/^yu-tora sandbox out/ , async ({ say, message , context}) => {
  const params = {
    TableName: 'yu-tora',
    Key: {
      id: dynamoId
    },
    ExpressionAttributeNames: {
      '#s': 'slackUser'
    },
    ExpressionAttributeValues: {
      ':slackUser': null
    },
    UpdateExpression: 'SET #s = :slackUser'
  };
  await docClient.update(params).promise();

  await say('Sandboxを開放したトラ😽');
});

使用状況を確認できる

使用状況の確認(使用中の場合)
使用状況の確認(空いている場合)

yu-tora sandbox info で現在のステージング環境の使用状況を確認できるようにしました。

app.message(/^yu-tora sandbox info/ , async ({ say, context }) => {
  const data = await docClient.get({ TableName: dynamoTableName, Key: { id: dynamoId } }).promise();
  const item = await data.Item
  if (!item) {
    await say('Sandbox環境は空いてるトラ😽');
    return;
  }

  const user = item.slackUser;
  const branch = item.branch || '';
  const sha = item.sha || '';

  if (user) {
    await say(`<@${user}> が使用中トラ😸 \`${displayBranchName(branch, sha)}\``);
  } else {
    await say(`Sandbox環境は空いてるトラ😸\n適用中のブランチは \`${displayBranchName(branch, sha)}\` だトラ😾`);
  }
});

まとめ

Slack上でデプロイすることができるので、だいぶ楽になりました😄 また、使用中であるかどうかと、使用中の場合は誰が使っているか分かるので、ステージング環境を使うまでの手間が削減できたと思います😊

今回の改善は、YOUTRUSTで月1日実施しているKAIZEN Day(詳しくはこちら)で実施したのですが、継続して色々と改善していけたらと思っています!

サービス成長に耐えうるリスト取得ロジックについて考える

こんにちは!YOUTRUSTでエンジニアをやっているやまでぃ(YOUTRUST/Twitter)です!

外は春の陽気が心地よく、部屋の中もそよ風が吹き抜けていてとても気持ちが良いです。

最近のYOUTRUST社の話なのですが、先日3年振りに全社合宿を湯河原で行いました。
現地集合現地解散とのことだったので、折角なので僕は家から片道90km6時間の道のりを自転車で往復しました。普段はオンラインで直接顔を見合わせない人達とも交流が持ててとても有意義な時間でした。

帰り道でぱしゃり。これの7倍くらい海が広がっていた。

さて今回の本記事ではスケーラブルなリスト取得ロジックについて書いていきます。

タイムラインの投稿やユーザー検索等、Webサービスでは何かとリソースのリストを取得する処理がありますよね。

「リスト取得なんて持ってくるだけじゃん?簡単じゃん?」かと思いきや、実はちゃんと気をつけて設計しておかないと、サービスの成長と共に重くなってしまいユーザー体験を著しく損ねてしまいます。

結構奥が深いリスト取得の話を少しだけ深ぼってみます。

Too long, don't read.

YOUTRUSTはパフォーマンスを気にしてリスト取得のロジックを色々工夫して頑張っているよ、という話です。

もっとこうした方が良いんじゃない?等ございましたら こちら からこっそり教えてください。

ソートとフィルターって大変だよね

何かしらのリソースのリストを取得する際にはソートとフィルター処理がよく要件として求められます。

  • ソート(並び替える)
    • 例. ABCDE→ACEDB
  • フィルター(絞り込んで数を減らす)
    • 例. ABCDE→ACD

例えば、タイムラインの投稿リソースの場合、投稿日時順にソートされているだろうし、自分がフォローしているユーザーの投稿に絞り込みが行われていることでしょう。

さて、このソートとフィルター機能を実現しつつ、どのようにリスト取得を行っていくかを考えていきます。

実現方法その1. 全件取得

まず最初に思い付くシンプルなものは、クライアントの要求する条件を満たすものを全て取得して全部返すやり方でしょう。実にシンプル。

サービスのリリースからしばらくの間はこの実装で問題ないと思います。

ですが、サービスの成長と共にこの方法は限界を迎えます…

  • リソース数の増加に伴い、ソートに時間がかかるようになる。
  • リソース数の増加に伴い、フィルターに時間がかかるようになる。
  • リソース数の増加に伴い、APIレスポンスサイズが大きくなり、通信時間が長くなる。
  • リソース数の増加に伴い、クライアント側でのレンダリング等に時間がかかる。

つまりユーザーさんからみたらサービスが「重くなる」のです。これは良くない。
「重いから」というマイナスな体験が先行してしまい、サービス本来の価値を知ってもらう前にブラウザのタブやアプリをそっ閉じして去っていってしまうかもしれない。まずい。

改善しよう改善しよう。

実現方法その2. 分割取得

条件を満たすリソースを「全件返すから」重くなるんだ!…ということで分割して返すことを思いつきます。所謂ページング処理です。

サーバーはクライアントからリクエストを受け取ったら条件を満たすリソースを全部返すのではなく、まず最初は1ページ目に含まれる分だけを取得して返します。

そして、もしユーザーさんがUAの画面をスクロール等して2ページ目を要求してきたら、その時に必要な分だけをまた取得して返します。

もしかしたらユーザーさんは2ページ目を要求せずに別の画面に遷移しちゃうかもしれないですしね。必要な分だけ返しましょう。全く無駄がないですね、素晴らしい。

…ですが、この分割取得方式を導入するとまた別の問題が発生します。

そう、リソースの「重複や欠損」問題です。

各ページの取得タイミングによってはソートやフィルター処理が参照する変数の値が変わり得て、ページ間でリソースの重複や欠損が発生してしまう可能性があります。

具体例でいうと下記のような感じです。

  • 時間 T1
    • この時点での実際のリソースの並び(A, B, C, D, E, F, G)
    • 1ページ目(1〜3件目)→(A, B, C)
  • 時間 T2
    • この時点での実際のリソースの並び(A, C, D, B, E, F, G)
      • T1から時間が経過しており、並びが同一である保証が無い。
    • 2ページ目(4〜6件目)→(B, E, F)
      • またBが返っている(重複)。Dが1ページ目の位置に移動していて取得できなくなっている(欠損)。

重複や欠損が発生する確率はまぁまぁ低いと見積もって「たまに重複や欠損がでちゃうかもだけど許容する!何も対処しない!」という選択肢を取るのも勿論ありだと思います。サービスの性質を考慮して判断すると良いと思います。

我々YOUTRUSTの場合は、確率が低そうとはいえ、システム側の都合でユーザーさんが不利益を被る(例えばユーザー検索結果に出てこなくてスカウトをもらう機会を逃してしまう等)のは許容しないと判断したので、この問題に真正面から向き合っています。

次にこの問題に対してYOUTRUSTがどう対処しているのかについて説明します。

リスト内リソースの重複・欠損を防ぐ対処法

結論から言うと「最初の1ページ目の取得時に2ページ目以降も全部計算しちゃってるよ!」です。

1ページ目の取得リクエストの処理時に、2ページ目以降のソートとフィルターも全部計算してそのIDだけを返します。(IDのサイズはリソース本体と比べて十分小さいので、全件返すことをサイズ的に許容できます)
この方法だと1ページ目の取得時に2ページ目以降のリソースと並びが全て確定するので、重複や欠損が生じません。
また2ページ目以降の取得はID指定で行うので高速にもなります(ソートやフィルター処理が行われず、ただ指定されたIDのリソースを返すだけなので)。

これにて一件落着!…かと思いきや、もちろんそんな事はなくて、今度は「2ページ目以降のソートとフィルター処理」が重くなる(スケールしない)という問題が発生してきます。

この問題を解決するために、そのリストの性質に応じた対応策を取っています。

最近作成されたリソースが大事なリストの場合(タイムラインの投稿等)

ソートロジックが、大まかには定数である作成日時に依存していると言えるので、リソース全体を時間範囲でリソース群に区切って扱うことができます。(取得タイミングによって並びが変わらないので)

そして1ページ目の取得時には最新の時間範囲のリソース群のみを検索対象とすることで、サービスの成長に伴うレコード数の増加を一定数に抑え込んでいます。(つまり2ページ目以降のリソース数が一定数に落ち着くので、計算量が爆発しにくいということ)

ユーザーさんの画面スクロールが進むにつれ、範囲内のリソース群内のリソースが分割取得されます。
その範囲のリソースが全て取得し終わったら、次の時間範囲のリソース群を取り出し、またこれを分割取得していきます。(二段階に分割取得しています)

全リソースが検索対象なリストの場合(ユーザー検索等)

2ページ目以降のソート・フィルター処理を非同期化することによって計算時間を隠蔽しています。

1ページ目の計算が終わったらAPI自体はすぐレスポンスを返して、2ページ目以降の処理は非同期ジョブに投げます。

クライアント側で1ページ目がレンダリングされユーザーがリソースを閲覧している間に、非同期ジョブがゆっくりと2ページ目以降の計算を行います。

ジョブの計算が終わったらWebSocketによりサーバー側からクライアント側にデータをサーバープッシュします。

この方式により、2ページ目以降のソート・フィルター処理という計算時間を隠蔽しています。

※YOUTRUSTのユーザー検索対象の母集団は「リクルーターの2次友達の和集合」であり、フィルターには「意欲の閲覧判定(とても複雑)」が入るので、検索処理がとても重たい。今はなんとかなっているが、今後サービス成長につれてどこまで耐えられるものか…これをここまで読んでくださっているエンジニアの方、タスケテクダサイ…!

終わりだよ

以上がYOUTRUST上でのスケーラブルなリストを実現するための設計概要です。
また機会があれば、詳細で具体的な実装例と共に解説するかもしれません。

こんな文字ばっかりの記事を最後まで読んでくれてありがとうございます!(感謝)

そんなあなたに僕が以前住んでいた所の近くのラーメン屋の写真を置いておきますね。多分200〜300杯くらい食べたんじゃないかなぁ。

中目黒で一番美味しい中華そば屋だと思っています。

それではまた次回の記事をお楽しみにしてていただければと思います!あざました!

実はYOUTRUSTのChrome拡張つくっていた件

こんちは!めろたん(YOUTRUSTアカウント, Twitterアカウント)です。

最近は忍者の本を買いました。

f:id:renyamizuno:20220411133423p:plain:w300
万川集海
youtrust.jp

忍者になるために頑張りたいと思います。

はい。


みなさんご存知だとは思うのですが、ちょいちょい前にYOUTRUSTのChrome拡張をだしていました!

chrome.google.com

もちろん皆さんいれてますよね!

入れてない人はいれてね!!!!!!

一応入れていない人に説明しておくと、

パッと思い浮かんだこととかをかんたんにすぐYOUTRUSTに投稿できる!というコンセプトの拡張になります~。

f:id:renyamizuno:20220311143847p:plain
Chrome上でかんたんに脳内メモを投稿できるという図

ページ内に引用して投稿したいサムシングがあれば、そのテキストを選択した状態で拡張を開くと

f:id:renyamizuno:20220311144057p:plain
「物語はちと?不安定」というワードを選択してそれを引用できている図

みたいな感じでURLと引用した文字が入った状態で投稿の画面が開いたりするとかそういう機能もあったりします!

\\!便利!//

ということで今日はこれをどう作ったかとか、そういう感じのことを書いていこうと思います!

Chrome拡張 is

Chrome拡張はまあChromeを拡張するソフトウェアというかプラグインというかそういうやつですね。

HTMLとCSSとJSでかけるのでwebエンジニアには親和性が高くて開発しやすいかと思います。

いろんな拡張がありますが、

chrome.google.com

が個人的にはめっちゃ好きです。

実際にどうつくったか。その軌跡。

なにか特別すごいことをしたいわけでもないので作りはとてもシンプルです。

投稿の画面には React を使用しています。

reactjs.org

create-react-app で適当に作りました。

create-react-app.dev

npx create-react-app my-app

React のプロジェクトがつくれるのでこれで概ね完成っすね()。

あとは「これはChrome拡張だよ~」としらせるために manifest.json が必要なのでそれを public 配下に追加します。

今回はポップアップで画面を表示したいので、 manifest.json

{
  // ...
  "action": {
    "default_popup": "index.html",
    "default_title": "YOUTRUST"
  },
  // ...
}

を追加します。

こうするとなんか表示されるはずです。

これで npm run build とかを実行してChrome拡張として動く状態のJS等々を書き出します。

その後Chromeの「拡張機能」から「パッケージ化されていない拡張機能を読み込む」を押して、 npm run build とかで吐き出された build ディレクトリを選択してやれば動くはず!

f:id:renyamizuno:20220311144633p:plain

と思ったのですが、上手く動きませんでした。

create-react-app で作った場合に build をすると、 ランタイムスクリプトがインラインで埋め込まれるらしくなんかそいつで落ちている感じでした。

なので package.jsonscriptsbuild を書き換えます。

 "build": "INLINE_RUNTIME_CHUNK=false react-scripts build",

みたいな感じでやってやると問題がなくなり、ポップアップがいい感じに表示されるようになりました。

あとはまあ普通に画面つくって行く感じで概ね完成という感じですね!

ということで投稿までは上手く動くようになりました。

あとは選択した文字の引用をやるだけです。

引用やるぞい

選択したテキストをいい感じに転記するには、ブラウザのタブに表示されているHTMLから選択したテキストを拡張のポップアップに持ってこないといけません。

この「タブで開いているWebページ」と「ポップアップ」の2つは別の世界にいるので、 Reactprops とか Redux とかそういうものでは送ることができません。

ではどのようにして送るかというと、 chrome.tabs.sendMessagechrome.runtime.onMessage.addListener を使ってメッセージのやり取りを行うことで達成しています。

developer.chrome.com

developer.chrome.com

まず「ポップアップ」を立ち上げたときに chrome.tabs.sendMessage で現在開いているタブで開いているWebページに対して「文字をくれ」というメッセージを送信します。 そしてそのメッセージを対象の「タブで開いているWebページ」上で受け取るために content_scripts というものを用意します。

この content_scripts はWebページに対して任意のjsを差し込むもので、これを使うことでChrome拡張でDOMの操作等を行えるようになります。 そして今回はこの content_scripts で先のメッセージを受け取って文字が選択されているかどうかを確認するようにします。

popup

// popup起動時に動くようにするためにuseEffectのなかにぶっこんでるコード
chrome.tabs.sendMessage(tab.id!, {action: 'YOUTRUST_GET_TEXT'}, (res) => {
  if (res.action === 'getSelectedText') {
    // テキストエリアにcontent_scriptから受け取った文字をセットする
    setContent(res.selectedText);
  }
});

content_script

const getSelectedText = () => {
  // getSelectionで選択されている文字があるかどうかみる
  const text = document.getSelection().toString();
  if (text.length > 0) {
    // URLとかもここでしか取得できないのでついでにとっちゃう
    return `>${text}\n${location.href}`;
  }
  // 選択されてなかったら空文字
  return '';
};

chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
  if (message.action === 'YOUTRUST_GET_TEXT') {
    sendResponse({
      action: 'getSelectedText',
      selectedText: getSelectedText(),
    });
  }
  return true;
});

あとはこの contetnt_scripts を埋め込むよ~というのを manifest.json に追記します。

{
  // ...
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"]
  }],
  // ...
}

こんな感じにすることで、popupを起動した際にタブ内で選択されている文字があればそれを取得してよしなにpopupに持ってくるというのができるようになります!*1

ストアに提出・審査

あとはストアにだすだけですね! 「chrome ウェブストア」につくった拡張機能をリリースするには、開発者として登録する必要があり「5ドルの登録料」を払えばおkです。
これは最初に払うものなのであとは特になにか払うとかは必要では無いはずです! ここまで行けばあとは拡張機能を審査に出すだけです!

特段難しいことはないですが、説明文等はある程度長くないとリジェクトをくらいますのでちゃんと書きましょう。(ちゃんと書かずに出したせいでリジェクトをくらった顔)

スクショやアイコンをちゃんと準備して審査を依頼したら、あとはのんびりお茶でも飲んで待ちましょう*2

僕は一回リジェクトをくらったせいか2~3週間待ちました()

そして審査が通れば晴れてリリース完了です!

そもそもなんでつくったの?

YOUTRUSTはキャリアSNSなので、ユーザーにコンテンツを投稿してもらうことが大事だよねというのがあります。
転職や副業につながるようにするためにという視点でも、ユーザー同士がYOUTRUST上でコミュニケーションを取って「友達になる」ことでそのチャンスが増えるというのがあります。(そのための手段として投稿をしてもらいたいというのがある)

ですが、事実として投稿数はそんなに多いわけではないですし、なかなかコミュニケーションをとるのも難しいというのが現状あります。

そこで「まずは投稿数が増えるような施策を考えよう!」というプロジェクトが立ち上がり色々考えていたのですが、 どうやったら増えていくのか難しいところでなかなかどうしたものか…と停滞していました。

そんな中で個人的に「まず気軽に投稿してもらう・投稿できるというのを印象つけるためにChromeに常駐させてしまえばよいのでは」と考え、 思い立ったが吉日ということで、スキマ時間をみてガシガシ作り「できたのでせっかくだしリリースしたいです!」ともって行ってリリースしたという流れでした。

まとめ

スキマ時間で初めたものの、古の知識しか持ち合わせておらず今どきな書き方をする必要があってその辺が少し大変でしたね。 まあとはいえ「許可を得るな謝罪せよ」精神でリリースまでいけたのはよかったなぁと勝手に思っています。

ということでメンテしないといけないものを勝手に一つ増やしたので、 Chrome拡張つくりてえよ!!!!という人もそうでない人も是非カジュアルに話しましょうということで、何卒🙏🙏🙏

youtrust.jp

youtrust.jp

youtrust.jp

youtrust.jp

*1:もちろんこれだけでは動かないので他にも色々書く必要があります。コアな所だけ抜いた感じです。

*2:といったけども何営業日かかかるのでのんびり気長に待ちましょう

エンジニアがプロダクトのことを考えたら、サービスもチームも前進した【マンスリーKAIZEN DAY】

※この記事は2021年12月にYOUTRUST JOURNALに掲載された記事の転載です。

「コードを書くのがエンジニアの仕事。でも、もっとサービスやプロダクトの根幹に関わってみたい……」

そう思うエンジニアは多いかもしれません。一方で、日々の業務に追われ目の前のサービスに向き合うことが精一杯という人も多いのではないでしょうか。

YOUTRUSTのエンジニアチームでは、メンバーの発案により「KAIZEN Day」という制度を取り入れたことで、エンジニア起点のサービス改善がぐんと増えたそうです。

いったい「KAIZEN Day」とは何なのか?制度を運用する、エンジニアチームの3人にお話を伺いました。

プロフィール

圓田直樹(エンジニア)
株式会社CaSy、株式会社Misoca(現、弥生株式会社) 、株式会社キャスターといったスタートアップを経て、2021年9月に株式会社YOUTRUSTに入社。サーバーサイドをメインに、フロントエンドやインフラ、ネイティブアプリ開発もできるマルチなエンジニア。

zoo(CTO)
エンジニアとして株式会社ディー・エヌ・エーに入社、その後株式会社MERY執行役員経験後、2021年7月に株式会社YOUTRUSTに入社。エンジニアのバックグラウンドを活かしたプロダクト組織拡大がメインミッション。

中村竜也(エンジニア)
株式会社ベイジ、株式会社COUNTERWORKSを経て、2021年5月に株式会社YOUTRUSTに入社。フロントエンドを主戦場としつつ、最近はFlutter開発にも着手している。副業で写真・動画撮影も。

KAIZEN Dayとは、優先順位を気にせず開発ができる日

f:id:YOUTRUSTinc:20220206201208p:plain

名古屋からフルリモートではたらくエンジニアの圓田
プライベートでiOS/Androidアプリの開発も行う


——まずは、「KAIZEN Day」とは何か教えていただけますか。

圓田直樹(以下、圓田):YOUTRUSTのエンジニアチームで月に1回行っている取り組みです。その日はチーム全員通常業務はせず、日々の業務時間内では着手しづらい開発に各自取り組む時間としています。

——日々の業務時間内では着手しづらい開発とは、例えばどういったものがあるのでしょうか。

圓田:日々の業務時間内だと、どうしても納期や優先順位によって「今やるべきタスク」が決まってくるんですよね。そのため、「アプリのこの部分気になるな……」と思う箇所が出てきても、自分の判断だけではすぐに動けないことの方が多くて……。

中村竜也(以下:中村):KAIZEN Dayができるまでは、僕は気になるところがあると隙間時間でこっそり直していたんです(笑)。でも、周りに隠れてこそこそ開発するのもストレスで。今はKAIZEN Dayのおかげで、周りの目を気にせず堂々と自分の判断で開発できるようになりましたね。

——KAIZEN Dayで取り扱うものの基準はありますか。

圓田:「それを行うことで、サービスが良くなるかどうか」という最低限の基準しか定めていません。あとは各々の自由にお任せしています。

KAIZEN Dayの日は、まず朝一で「今日はこんな開発をします」というのを各自Slackで共有して、あとは就業時間まで黙々と作業することが多いですね。他の人と喋ったほうが集中できる人や、誰かに相談しながら進めたい人はオンラインで話しながら進めることもあります。KAIZEN Dayでは、やることも、やり方も自由度を高くしているんです。

——個人の判断で開発ができるのは魅力的ですよね。一方で、自由度が高い分、運営側はチームの統率が取りづらかったり、メンバーはどう動いていいか分からなかったりといった問題は発生しないのでしょうか?

中村:今のところ、そのような問題は発生していないですね。他者に何かをGIVEしたい、というエンジニアが集まったチームだからかもしれません。ユーザーさんのためとか、社内のメンバーのためとか、自分の強みを活かして、「周りにどんな貢献ができるか」を常に考えている人が多いんですよね。

zoo:エンジニアチームだけでなく、YOUTRUST全体としてサービスの先にいるユーザーを見る文化が根付いているのかな、と思います。採用面でもそれは重視していて。「エンジニアだから機能のことだけ考える」のではなくて、それを実際利用するユーザーに何を還元できるかを一緒に考えてくれる方とお仕事ができるとうれしいですね。

エンジニアの専門性×ユーザーを思う力=新しい価値

f:id:YOUTRUSTinc:20220206201524p:plain

最近はもっぱらFlutterエンジニアの中村
ファーストキャリアがパタンナー(服の型紙づくり)というクリエイティブな経歴

——KAIZEN Dayをきっかけに生まれた機能やサービスがあれば教えてください。

圓田:ユーザーさん向けの開発だと、YOUTRUSTの投稿をTwitterにシェアするときに、自動的に投稿主のTwitterアカウントにメンションが飛ぶとか、表示速度を少し早くするとか……

社内向けには、営業やCSのメンバーが使いやすいように管理画面をアップデートしたり、もう使っていない機能を整理したりもしています。プログラム言語やフレームワークのアップデートを行うこともありますね。

——一番印象に残っている開発はありますか?

中村:弊社のCSチーム向けの開発をしたときですね。CSで利用しているツールを改善をしたら、社内に歓声が沸き起こったんです。その開発を担当したエンジニアは、しばらくCSチームのメンバーから「神」と呼ばれていました(笑)

通常業務だと、どうしても優先順位的に社内向けの開発が後回しになってしまいがち。KAIZAN Dayを活用すると、このように社内の作業環境を改善することに全力を注ぐこともできるんです。

また、YOUTRUSTには良いことがあったら社内全体で盛り上げる文化があります。KAIZEN Dayで取り組んだCSチーム向けの開発も、一つひとつは小さなもの。でも、それをチームのみならず会社全体で盛り上げてくれて……その光景を見ると、純粋に"やってよかった"と嬉しくなりますよね。

zoo:YOUTRUSTのエンジニアは、開発だけでなく「もっと施策のことを考えたい、プロダクトのことを考えたい」という人がたくさんいます。エンジニアの専門性にそういう考えが掛け合わさると、新しい価値を生み出せると思うんですよね。だから、KAIZEN Dayのような取り組みも出てきたのかもしれません。

「エンジニア」の枠を超えて活躍する人が多い

f:id:YOUTRUSTinc:20220206201817p:plain

学生時代は手品サークルに所属し、大掛かりな仕掛けを得意としていたCTOのzoo
ゲリラ開催する社内向けラジオ「zooラジオ」が人気

——「サービスの先を考える人が集まっている」など、これまでお話を伺っている中で、YOUTRUSTのエンジニアチームには独自の魅力があるのかなと感じました。実際にエンジニアチームの一員として働くみなさんは、どんなチームだと感じていますか。

圓田:既存の状態に満足せず、より良くしていこうという人が多いですね。目の前のサービスに関してはもちろん、開発の進め方やコミュニケーションの取り方でもその姿勢を持っている人が多いと思います。

——確かに、YOUTRUSTのエンジニアはコミュニケーションを大切にする人が多い印象です。

zoo:例えば、チームの生産性をあげるためにミーティングの時間を短縮しようって議題があがったとき。今はSlackなどのチャットツールがどんどん発達してきているので、もしかしたらミーティングの時間はゼロでも問題なくチームは運用できるかもしれないですよね。

でも、生産性をあげるのと同じように、顔を合わせて話す時間も大事だと思っている人がチーム内には多いですね。リモートワークがメインになった今でも、ハドルやZoomを利用したオンライン上のコミュニケーションはよく取っています。

——コミュニケーションを大切にする他にも、チームの特徴はありますか。

中村:「エンジニア」という肩書だけに囚われずに、個々でできることを考える人が多いですね。エンジニアって、一般的には「コードを実装する人」ってイメージがあると思います。でも、YOUTRUSTでは自ら施策を考えたり、PdMの役割を担ったり、組織を束ねたりと「エンジニア」以外の自分の強みを活かして活躍している人がたくさんいるんです。

また、YOUTRUSTに入社してから初めてエンジニア以外のことにチャレンジするという人もいます。今後エンジニアの枠を超えたチャレンジをしてみたい人にもおすすめできる環境だと思いますね。

「信頼される人が報われる転職市場に」するため、エンジニアが価値発揮できるチーム

——最後に、今後YOUTRUSTのエンジニアチームにどうなっていってほしいか、みなさんの考えをお聞かせください。

圓田:今後事業が拡大するにつれて、会社の規模もフェーズもどんどん変化すると思います。それでも、自分で問題点を見つけて「もっとプロダクトを良くしていこう」と思うメンバーが集まるチームだといいですね。

zoo:圓田さんが言っていることと近いのですが……。ただコードを書くだけではなく、エンジニアがきちんとプロダクトに対してバリューを発揮できるチームでいたいし、そうなるようチーム一丸となって努力をしていきたいです。

中村:YOUTRUSTは、「信頼される人が報われる転職市場に」というミッションを掲げています。そのミッションに共感していただき、実現に向けて「エンジニアとして何ができるんだろう」と考えてくれる人がチームに集まってくれるとうれしいですね。

YOUTRUSTエンジニアブログ始めます!

こんにちは。YOUTRUSTのCTOのzoo(@zoopon1986)です。エンジニアブログ始めます。

 

YOUTRUSTとエンジニア

YOUTRUSTでは、「信頼される人が報われる転職市場に」というミッションを掲げ、キャリアの機会を広げる"キャリアSNS"や法人向けに副業・転職のスカウトサービス(CareerTechと呼んでます)を提供しています。

 

そのようなYOUTRUSTを開発しているエンジニアは、副業や業務委託の方を合わせて15名ほど。toCプロダクトをつくるSNS事業部と、toBのキャリア事業部に所属しているエンジニアはそれぞれの事業の目標達成に向けてプロダクト開発を行い、CTO室に所属しているエンジニアは共通基盤を担当しています。また、サービス提供に用いている技術は、AWSRails、React、Flutterなどです。

 

YOUTRUSTのエンジニアブログ

少しずつエンジニアの数が増えてきて、エンジニアブログを始められることになりました。エンジニアメンバーや組織の雰囲気、あるいはYOUTRUSTで使われている技術の紹介など、わいわいと発信していきたいと思います。また、それらを通して、少しでも誰かの役に立てたら嬉しいと思います。

 

YOUTRUSTのエンジニアブログをお楽しみに!

今後、少しずつ記事を発信していきます。どんな内容になるのか、僕自身も楽しみにしています。みなさまも、ぜひ楽しみにお待ちください。

 

herp.careers