RareJob Tech Blog

レアジョブテクノロジーズのエンジニア・デザイナーによる技術ブログです

マナビアップデートソン2023

はじめに

こんにちは!CEOの山田です。

11月8日、9日に全社合宿を行ない、そこで弊社ミッションに因んで名付けたハッカソン「マナビアップデートソン2023」を開催しました。 場所は「クロス・ウェーブ府中」さんにお世話になりました。宿泊可能な大規模な研修施設で、建物は綺麗で開放感もある造りで、宿泊した部屋も広くて眺めもよく、懇親会も施設内で開催でき、満足出来る施設でお勧めです。

目的

合宿でハッカソンを開催した目的は、チームビルディングとアイディアの掘り起こしです。

チームビルディング

弊社はリモート主体の勤務体制をとっており、プロジェクトベースで業務を推進しています。対面でのコミュニケーション機会は限られていますが、今回の合宿で長時間のグループワークや懇親会を通じて、組織の活性化と心理的安全性の高い環境を目指しました。

アイディアの掘り起こし

深くプロダクトに関わる人たちが持つアイディアを引き出し、それを具体化するためにハッカソンを設けました。チーム活動を通じてアイディアを洗練させ、実現可能なものへと発展させることが目標です。

開催概要

合宿前知見共有

合宿前には、業界動向や技術トレンドに関するプレゼンテーションを5人のメンバーに行ってもらいました。これは、当日をアイディア決定作業だけで終わらせないための準備です。5人の中には、お願いして親会社であるレアジョブの中村CEOにも発表して頂きました。中村さんだからこそ知っている内容が多く、盛り上がりました。

ハッカソン概要

  • 3もしくは4名1チーム
  • 普段関わらない人同士のメンバー構成
  • 制限は、EdTech領域であることのみで、英語学習でなくてもOK
  • 一日目は制作、二日目は発表(二日目は会議室が12時までだった)
  • 評価軸
    • インパクト(有用性、利便性)
    • ユニーク(独創性、先進性)
    • マーケット(市場性、実現性)
  • 評価方法
    • 全員の投票で、各チームの評価軸を5段階で採点
    • 3つの評価軸と総合点の最優秀賞を選出

結果

CTO率いるチームが最優秀賞と2つの評価軸で圧倒的な成績を収めました。 ただ、発表された作品は、想像以上にクオリティが高く、みな業務の合間で真摯に向き合って合宿に臨んだことがわかりました。 多くの作品は、次の企画に入ることになる可能性が高いので、成果については非公開になります。

感想

イベントでは予期せぬトラブルに直面することもあります。今回は、ランチのお弁当が足りないという問題が発生しました。この点については、数量の見落としでご迷惑をおかけし、申し訳ありませんでした。しかし、このトラブルを通じて、チームとしての対応力が高まったと感じますね(笑)。

このイベントは、リアルな交流と新たな学びを得る貴重な機会であり、非常に楽しいものでした。今後もこのような取り組みを続けていきたいと思います。

集合写真

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

WordWiz - 子供の学習意欲を高める新しいサービス

こんにちは、ディズニーパークとドナルドダックをこよなく愛するCIOの岩堀です。今日は初の試みで行ったプロジェクトについてお話ししようと思います。それは、私たちの会社が初めて公募にて有志が集まってスタートしたプロジェクト「WordWiz」です。これは、K12領域において、子供たちが学んだ単語を使ってオリジナルの絵本を作成し、親子で楽しみながら学ぶことができるサービスです。

wordwiz.rarejob-tech.jp

サービス導入背景

K12市場は、まだまだ成長の余地があります。そこで、私たちは「WordWiz」を通じて、この市場に新しい風を吹き込むことを目指しました。このアイデアは、社内公募プロジェクトから生まれ、チームの情熱と創造性が詰まっています。ドナルドダックのように時にはちょっとドジながらも、常に前向きに挑戦する精神でこのプロジェクトに取り組みました。

技術的な挑戦

このプロジェクトでの、フロントではこれまでレアジョブでは使っていなかった技術を採用し、バックエンドではモダンな形でAWSを中心に構築しました。これらの技術を使いこなす過程で、私たちも大きく成長しました。

フロントエンド
  • Nuxt3 x Vue3
  • TailwindCSS x DaisyUI
  • Pinia
  • Bun
バックエンド
  • Go
AWS
  • ECS
  • ALB
  • CloudFront
  • Lambda
  • SQS
OpenAI
  • GPT-4
  • DALL-E3

サービス提供目的、狙い

WordWizは、K12領域の子供とその保護者を対象に、学習体験を豊かにすることを目指しています。子供たちが楽しみながら単語を学び、親子でオリジナルの絵本を作成することで、学習への興味を深めることができます。 私たちの目標は、学習をもっと楽しく、もっと身近なものにすることです。WordWizを通じて、子供たちが自分のペースで学び、親子で共有できる経験を提供することで、学習への新たなアプローチを提案し、応援したいと思っていただけるようなサービスになることを目指しています。

絵本イメージ

今後の展望

WordWizは現在、テストマーケティングの一環としてローンチし、ユーザーニーズを探っています。私たちは、ユーザーの声を大切にし、サービスの改善と進化を続けていきます。そして、これからもドナルドダックのように、時には失敗を恐れず、常に新しい挑戦を続けていきます。

このプロジェクトは、ただの仕事以上のものでした。私たちの情熱と、子供たちの笑顔を想像しながらの開発は、まさに魔法のような体験でした。WordWizを通じて、多くの家庭に新しい学びの形を届けられることを心から楽しみにしています。

We're hiring! 弊社では、一緒に働いてくださるエンジニアを募集しています。

rarejob-tech.co.jp

Amazon Bedrock Prototyping Campに参加してきました!(BedrockとKendraの簡易ハンズオン付き)

はじめに

SMART Method・PROGOS開発グループの奥山です。

京都に引っ越して3ヶ月経ったころ、友人が京都に来たと言うので坐禅に誘いました。

友人は「パートナーがこっちにできたからついでに会いに来た。パートナーと予定があるから坐禅は行かぬ。」と返事をくれました。

さて、私の心もこの頃の気温も急に冷え込んできましたが、生成系AI界隈は非常にアツいです。

そんな中、AWS Japan様から招待いただき、「Amazon Bedrock Prototyping Camp」に参加してきました!

以下、参加レポートとなります。

コンテンツ

  1. Amazon Bedrock Prototyping Campのコンテンツ概要
  2. Bedrock・Kendraのハンズオン付き説明
  3. 開発する際によかったリポジトリやドキュメント
  4. 感想

Amazon Bedrock Prototyping Campのコンテンツ概要

Amazon Bedrock Prototyping Campは

  1. 生成系AIをアプリケーションに組み込む際のビジネス的・エンジニア的な観点
  2. Bedrockの説明
  3. プロンプトエンジニアリングとRAGについて
  4. Bedrockハンズオン
  5. Kendraの説明
  6. Bedrock、Kendraを利用したプロトタイピング

を7時間でやるイベントでした。

Bedrock・Kendraのハンズオン付き説明

実際に受けた説明をもとに、BedrockやKendraの説明をしていきます。

Bedrock

特徴(+解釈)として

  • 主要な基盤モデルをサポート
  • 独自のデータで基盤モデルを非公開でカスタマイズできる
  • GDPRへの準拠やHIPAAの適格性などの標準への対応

があります。

SDKなどを通じてAPIコールすることで利用可能です。

Kendra

データ自体が構造化データ・非構造化データなのかを気にせず放り込めて、それを検索可能にするサービスです。

検索エンジンには機械学習を使っているとのことです。

コネクタが非常に強力で、GoogleDrive、Confluence、S3、RDSなどに対応しているだけでなく、手軽さもあります。こちらがデータ構造をやたら気にする必要なく様々なデータソースから取り入れられるというのが非常に魅力的です。

また、KendraはQueryAPIとRetrieveAPIがあります。

詳細な説明は公式ドキュメントに譲りますが、RetrieveAPIの方がより多く意味的に関連するドキュメントを取得してきます。QueryAPIもRetrieveAPIも意味的に関連するドキュメントを取得しますが、QueryAPIは1つのドキュメントから1つの抜粋なのに対して、RetrieveAPIは1つのドキュメントから関連性の高いものを複数抜粋できるところが特徴となります。

BedrockとKendraをどう組み合わせて使うか?

つまるところ、RAGが実装できます。

Prompt Engineering Guideから引用してみます。

RAG は入力を受け取り、ソース(例えばウィキペディア)が与えられた関連/証拠立てる文書の集合を検索します。文書は文脈として元の入力プロンプトと連結され、最終的な出力を生成するテキストジェネレータに供給されます。これにより RAG は、事実が時間とともに変化するような状況にも適応できます。LLM のパラメトリック知識は静的であるため、これは非常に有用です。RAG は言語モデルが再学習を回避することを可能にし、検索ベースの(文章)生成によって信頼性の高い出力を生成するための最新情報へのアクセスを可能にします。

質問などの入力を受けた際に、参照データを検索した結果を結合して、それをもとに回答を生成してもらう仕組み、という理解で行きます。

KendraにQueryやRetrieveのAPIを用いて取得したデータをBedrockに渡すプロンプトと合わせて質問することで、RAGを実現可能です。

弊社のブログだと、LangChain(OpenAPIのGPT3.5-turboモデル利用)とChromaDBでハンズオンの記事がそれっぽいことをやってたなと思います。

BedrockとKendraのハンズオン

東京リージョン(ap-northeast-1)にて、Bedrock・Kendra共に、AWSコンソールからセットアップし、実際に呼び出して動作するところまでを試してみます。

ぜひお手元で試してみてください!

Bedrockのセットアップ

AWSのBedrockコンソール「Model Access」をクリックします。

「Manage model access」をクリックし、モデルを利用できるようリクエストします。

これで完了です。

リージョンによって利用可能モデルが違うので、公式ドキュメントをご確認ください。

ハンズオン環境

イベントで利用したSageMakerのノートブックを紹介します。

つまるところ、「AWSのサービスを利用する際に利用する諸々の変数セットアップをすっ飛ばして利用可能なJupyterNotebook」です。

SageMakerのコンソールを開き、メニューバーから「ノートブックインスタンス」を選択します。

作成には少々時間がかかります。

作成されたら、メニューから作成したノートブックを選択して「アクセス許可と暗号化」を探します。

IAMロールでの設定を通じて、ノートブックにBedrockとKendraのロールを全許可で追加します。

イベント会場では、「インラインポリシーを作成」から実行しました。

JSON形式だと下記のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
                "bedrock:*",
                "kendra:*"
            ],
            "Resource": []
        }
    ]
}

検証ではこちらを貼り付けてご利用いただければと思います。

ただし、本番ではちゃんと制限をかけて運用する必要があるので、適宜ご変更ください。

Bedrockのコード

import boto3
import json

# bedrockクライアント初期化
# bedrock_client = boto3.client(service_name='bedrock')
bedrock_runtime_client = boto3.client(service_name='bedrock-runtime')

prompt = "日本で一番高い山はなんですか?"

body = json.dumps({
    "prompt": prompt,
    "max_tokens_to_sample": 300,
    "temperature": 0.1,
    "top_k": 250,
    "top_p": 1,
    "stop_sequences": ["\n\nHuman:"]
})
modelId = "anthropic.claude-instant-v1"  # change this to use a different version from the model provider
accept = "application/json"
contentType = "application/json"

# モデル呼び出し
response = bedrock_runtime_client.invoke_model(
    body=body, 
    modelId=modelId,
    accept=accept,
    contentType=contentType
)

response_body = json.loads(response.get('body').read())
print(response_body.get('completion'))


# LangChainパターン
from langchain.chat_models import BedrockChat
from langchain.schema import HumanMessage

llm = BedrockChat(
    client=bedrock_runtime_client,
    model_id="anthropic.claude-instant-v1",
    model_kwargs={
        "temperature":0.1,
        "max_tokens_to_sample": 1000},
)

result = llm([
    HumanMessage(content=prompt)
])

print(result.content)

Bedrock利用する際に重要なこと

端的に言うと、「プロンプトをしっかり検証する。そのためにプロンプトエンジニアリングを把握する。」です。(とはいえ、これはLLM全般を利用する際に言えることだと思います。)

当日配布されたコードをそのまま貼り付けておくので、是非お手元で改善されていく様を観察してみてください。

比較が楽になるよう、メソッドを定義します。

def invoke_claude(text, max_tokens_to_sample=1000): 

    body = json.dumps({
        "prompt": f"\n\nHuman:{text}\n\nAssistant: ",
        "max_tokens_to_sample": max_tokens_to_sample,
        "temperature": 0.1,
        "top_p": 0.9,
    })

    modelId = 'anthropic.claude-instant-v1'
    accept = 'application/json'
    contentType = 'application/json'

    response = bedrock_runtime.invoke_model(body=body, modelId=modelId, accept=accept, contentType=contentType)

    response_body = json.loads(response.get('body').read())

    return response_body.get('completion')[1:]

初期プロンプト

prompt_template = """
以下のようなシステムのアーキテクチャを考えてください。  
システム概要: {about}
システム規模: {scale}  
機能: {features}
"""

prompt = prompt_template.format(
    about="衣料品を販売するECサイト", 
    scale="ピーク時には毎分10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

改善1回目のプロンプト:ロールを与えている

prompt_template = """
あなたは熟達したシステムアーキテクトです。初心者にとっても専門用語を噛み砕いて分かりやすい説明をすることで有名です。
以下のようなシステムのアーキテクチャを考えてください。 
システム概要: {about}
システム規模: {scale}  
機能: {features}
"""

prompt = prompt_template.format(
    about="衣料品を販売するECサイト", 
    scale="ピーク時には毎分10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

改善2回目のプロンプト:タグを利用し、プロンプトを構造化する

prompt_template = """
<Instruction>
あなたは熟達したシステムアーキテクトです。初心者にとっても専門用語を噛み砕いて分かりやすい説明をすることで有名です。
システムの概要、規模、機能の情報をもとにお客様の要求を分析し、セキュリティ・パフォーマンス・運用性・信用性・コスト最適といった観点でアーキテクチャを考案してください。
また、高校生にもわかるように、専門用語を噛み砕いて説明してください。
</Instruction> 
<Requirements>
    <About>
        {about}
    </About>
    <Scale>
        {scale}
    </Scale>
    <Feature>
        {features}
    </Feature>
</Requirements>
"""

prompt = prompt_template.format(
    about="ECサイトのためのウェブサイト", 
    scale="ピーク時には毎秒10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

Kendraのハンズオン

Kendra自体のセットアップやコネクター自体は、コンソールで直感的に操作できるので、注意点だけにとどめます。

Kendraのセットアップ手順はざっくりと

  1. Indexの作成
  2. Indexにコネクターを通じてデータを投入する

です。

QueryやRetrieveのAPIを利用する際、利用する言語をデータ投入時の言語に合わせないと取得が0件になりました。

弊社はデータをjaで入れましたが、QueryAPIは言語指定しない場合、enで取得する仕様です。

そのため、当初SDK経由で利用していたとき、言語設定をjaにしていないことが原因で、取得が0件のケースに遭遇しました。

データ投入の際の言語設定は、下記写真の画面からできます。ご注意ください。

下記は、イベント当日、弊社がプロトタイピングする際に利用したコードになります。

弊社は当日、自社のConfluenceのデータを用いるため、jaでデータを入れました。

KendraのIndexIDが必要なので、対象のIndexを選択して、Index Settingsの項目から探してください。

import os
from typing import Dict, Literal

import boto3

kendra_client = boto3.client("kendra", region_name='ap-northeast-1')

indexId = 'KendraのIndexIDを入れてください'

kwargs = f"""{question}"""

response = kendra_client.query(
    IndexId=indexId,
    QueryText=kwargs,
    AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },
    PageNumber=1,
    PageSize=20,
    DocumentRelevanceOverrideConfigurations=[
        {
            'Name': 'string',
            'Relevance': {
                'RankOrder': 'DESCENDING'
            }
        },
    ],
)

# print(response)
# print(response['ResultItems'])

for result in response['ResultItems']:
    print(result['DocumentId'])
    print(result['DocumentTitle'])
    print(result['DocumentExcerpt']['Text'])
    print(result['DocumentURI'])
    print(result['DocumentAttributes'])
    print(result['ScoreAttributes'])
    print(result['DocumentTitle'])

Kendraにリクエストする箇所のコードに注目します。

response = kendra_client.query(
    IndexId=indexId,
    QueryText=kwargs,
    AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },
    PageNumber=1,
    PageSize=20,
    DocumentRelevanceOverrideConfigurations=[
        {
            'Name': 'string',
            'Relevance': {
                'RankOrder': 'DESCENDING'
            }
        },
    ],
)

特に

AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },

の部分は、「Kendraのデータを日本語で検索する」場合必要となります。

以上、ハンズオンでした。

開発する際によかったリポジトリやドキュメント

Bedrock

正直なところ、Bedrockについてはプロトタイピングする際に困ったことが特にありませんでした。(と言うのも渡されたサンプルが充実してたので・・・)

公式のGithubリポジトリでよくまとまっているのはこちらかと思います。

github.com

Kendra

2つの公式ドキュメントが役立ちます。

1つ目はKendraの該当するAPIのドキュメントです。

2つ目はSDK for Python自体のKendra部分のドキュメントです。

1つ目でKendraのQueryAPIのリクエスト構造を把握した上で、2つ目でどうSDKに落とし込むかを把握できます。

そのほか有用なGithubリポジトリ

AWSは公式のGithubリポジトリを有してます。

実際に紹介されたものをいくつか載せます。

https://github.com/aws-samples/generative-ai-use-cases-jp

https://github.com/aws-samples/bedrock-claude-chat

https://github.com/aws-samples/simple-lex-kendra-jp

イベント終了後に読んでから気付いたのですが、スライドの一番後ろにあったこちらのWorkshopも非常に良いです。(KendraをSDK for Pythonで利用する際のサンプルコードも乗ってます。)

catalog.us-east-1.prod.workshops.aws

感想

イベントに参加したことで、細かいテクニックから自社サービスの見方、開発する際のマインドセットに至るまで、さまざまな気づきを得られました。

個人的に、LLM導入の肝はプロンプトエンジニアリングである、と気づけたのは非常に大きかったです。(今後のLLMの発展でこの見解が覆ることもあるかもしれませんが。)

同時に、プロダクト価値の向上に資する開発とは何か?に対する手の動かし方の見識を広める入り口に立てた気がして、気分が非常に高揚しました。

手を動かして必死に導入しようと考える作業をもっとやりたいなあと思いました。

最後に

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

「少人数エンジニア組織でサービス成長させるには?座談会」 に登壇しました

はじめに

こんにちは、 DevOps グループの中島です。
AWS 社主催のイベントでつながったココナラ社の方よりお誘いがあり、勉強会を共同主催しました。 今回はその登壇レポートになります。

ココナラ テックブログでも執筆いただきました。
「ココナラ×レアジョブテクノロジーズ+AWS 少人数エンジニア組織でサービス成長させるには?座談会」を開催しました!

connpass リンク: ココナラ×レアジョブテクノロジーズ+AWS 少人数エンジニア組織でサービス成長させるには?座談会

内容

以下のテーマについて、それぞれレアテク社、ココナラ社で交互に LT する形式で行われました。 (言葉の選び方が上手だなあと感じます)

  • 少人数でもサービスを安定運用?超具体How to+やっぱり辛いこと
  • 技術負債って正直どうする?限界と現実、究極天秤の実情
  • 少人数の成長組織で戦い抜く秘訣

各 LT の内容は以下のとおりです。

★少人数でリスタート! DevOps チームの工夫と実践 (株式会社レアジョブテクノロジーズ 中島)

私からは少人数チームにおけるミッションの策定、稼働の削減、タスクの選定方法についてお話させていただきました。

★少人数で複数サービス運用するための日々の取り組み (株式会社ココナラ 吉川さん)

ココナラの吉川さんからは、AWS インフラ運用にまつわる具体的な取り組みについて発表がありました。
Terraform の plan 結果が自動でプルリクに貼り付けられる仕組みは参考になりました。 当社では AWS CDK を利用しているので、cdk diff の結果を貼り付けるのをやってみようと思います。

★大きく返す技術負債 システムリプレイスとその後のはなし (株式会社レアジョブテクノロジーズ 鈴木)

当社の鈴木からは、大規模リプレイスを行った際の進め方やそこで学んだ知見について発表させていただきました。

★スロークエリ撲滅委員会 (株式会社ココナラ 橋本さん)

ココナラの橋本さんからは、パフォーマンス委員会を設けてスロークエリに対処した具体的な方法について発表がありました。
Active Record を使っている場合に、遅い SQL から対象のコードを特定するのに苦労するのはどこでも共通の課題があるなと感じます。

★少人数チームで行う機械学習モデルの保守と新規R&D (株式会社レアジョブテクノロジーズ 齋藤)

当社の齋藤からは、機械学習モデルが増え続け運用が複雑になっていく中で、どのように少人数で対応しているかについて発表させていただきました。

★品質向上のためのモニタリング改善 X-Ray導入物語 (株式会社ココナラ 光吉さん)

ココナラの光吉さんからは、OpenTelemetry Ruby with AWS X-Ray の導入時に工夫した内容について発表がありました。
OTEL の SDK にモンキーパッチを当てて、足りない機能を追加してしまうところに高いエンジニアリング力を感じます。

★GenerativeAIを活用した開発生産性向上 (アマゾン ウェブ サービス ジャパン合同会社 大磯さん)

最後に AWS 社の大磯さんから Generative AI 関連 AWS サービスの紹介がありました。
CodeWhisperer がコードの diff を見てプルリクにコメントするデモをされていて、 こういった定形な文書作成の半自動化ができるとだいぶ楽ができるなと思います。

最後に登壇者で集合写真を一枚。

感想

コロナ禍からのリモートワークの流れもあり、久々に勉強会にリアル参加しました。
登壇者との交流は、ブログ記事を読むだけでは分からない生の情報が得られ、大変良い刺激を受けることができました。 ココナラの登壇者さんは魅力的なエンジニアの方ばかりで、機会があればまた技術的な話で親交を深めたいですね。
今後も定期的にこういったイベントに参加していきたいと思います。

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

PHPカンファレンス2023 でブース出展してきました

こんにちは。レアジョブ英会話開発グループの鈴木です。

前回の投稿でお知らせしていたとおり、10/8 (日) に開催されましたPHPカンファレンス2023にてブース出展をしました。
当日は多くの方にお越しいただきカンファレンス運営スタッフ、スポンサーブースの皆さまお疲れさまでした。そしてご来場された皆さまありがとうございました。

今回はノベルティとしてステッカー、チョコ、書籍、不織布バッグを用意しました。 不織布バッグは他企業ブースのスタッフの方にも好評をいただきました。

好評だった弊社ロゴ入りバッグ

弊社は2018年にもブース出展しており、そのときは英語に関する質問をさせていただきました。
コロナ禍を経て皆さまの英語との関わりにどのような変化があったかを可視化できたらなと思い、今回も英語に関する質問をさせていただきました。

2023年の質問結果

前回と同じ「仕事で英語を使う?」という質問を設けました。ここでは「英語のドキュメントを読むこと」も YES に含めて回答していただきました。
前回同様に YES と回答される方が多い質問ではあるのですが、「話す」「書く」で利用する方は比較的少なく、「読み」での利用時はChatGPTを利用して翻訳しているという方が多かったです。

AIが多くの作業を肩代わりしてくれる時代に、英語を習得することだけが目標ではなく、学習者がマナビを通じて得た能力や経験によって、グローバルに活躍できることの意味を再考する機会となりました。

それ以外にも CEFR の認知度やレアジョブ英会話の利用経験に関して来年はもっと YES をもらえるよう、蓄積されたデータとAIの技術を駆使して、より充実した学習体験をこれからも提供していきます。
そして引き続きPHPコミュニティへの貢献も継続していきます💪

We're hiring!
私たちと一緒に「マナビ、アップデート」してくれるエンジニアを大募集しています。
rarejob-tech.co.jp

レアジョブテクノロジーズはPHPカンファレンス2023に協賛します

こんにちは。三上( 三上 智's Wantedly Profile )です。

レアジョブテクノロジーズは 10月8日(日)に開催される PHPカンファレンス2023 にシルバースポンサーとして協賛します。

2019年はブロンズでの協賛でしたので、ブース出展は2018年(ゴールド)から5年振りとなります。

2018年の様子はこちら appeal.rarejob.co.jp

レアジョブテクノロジーズは、PHP以外にもプロダクトや機能に応じて Go, Vue.js, TypeScript など多様な技術スタックを採用していますが、現在でも多くのシステムはPHPで動いています。

2022年にレアジョブの子会社として誕生したレアジョブテクノロジーズですが、 メイン言語であるPHPの最大のカンファレンスに協賛し、オフラインでのコミュニケーションから私たちのプロダクトや組織の魅力を発信したいと考え、協賛に至りました。

また、参加者の皆様にレアジョブ英会話を知って頂き、英語学習/教育、EdTech、そして弊社に一人でも興味を持って頂けたらうれしいです。

当日は、会場にてブースを出展いたします!素敵なノベルティを用意してお待ちしておりますのでぜひお立ち寄りください。

ビルドツールをLaravel MixからViteに移行

こんにちはフロントエンドグループの大谷です。

自宅の備え付けのエアコンが古く、スイッチを入れてから10分くらい起動しなくて困っています。 猛暑日が続いているので起動は高速であってほしいものですね。。

プロダクト開発においても、歴史を重ねるとビルド速度が遅くなることがありますね。 今回はそんな課題を抱えていたリポジトリに、速いと評判のViteを導入した話について書いていきたいと思います。

Viteとは何か

Vue.jsの開発者でもあるEvan You氏が開発したビルドツールです。

  • VueやReact等多くのフレームワークをサポートしている
  • Laravel 9以降はLaravel Mix→Viteが標準
  • バンドル不要で開発サーバーの起動が早い
  • HMRが修正分のみを適応するため、モジュールの総数に関係なくかなり高速

(引用:https://ja.vitejs.dev/guide/why.html )

どんなことをやったのか

課題になっていたこと

今回対象となったリポジトリでは一部の機能がVueで作られています。SCSSファイルとVue・jsファイルがLaravel Mixでのビルド対象となっています。 このリポジトリではビルドの工程がCIにのせられておらず、ローカルでのビルドが必要になっています。

管理している範囲が広く、また歴史のあるシステムのため下記のようにファイル数が肥大化している状況でした。

SCSSファイル数 ビルドツール Nodeバージョン 構成
343 Laravel Mix5系 v12.22.1 MPA

Vue3のアップデートも計画しているためNode16以上へのアップデートが必要があり、前段の作業としてNodeのバージョンを作業実施時にlatestだったv18.16.0に更新したところ元々時間がかかっていたVueとSCSSのトランスパイルに要する時間が更に長くなる結果となっていました。

Laravel Mix5系:Vue + SCSSのを対象にした場合(productionモード)

Node12 + node-sass + Vue Node18 + Dart sass + Vue
ビルド時間 1分48秒 8分56秒

Laravel Mix5系:Vue + SCSSのを対象にした場合(developmentモード)

Node12 + node-sass + Vue Node18 + Dart sass + Vue
ビルド時間 1分44秒 1分42秒

Laravel Mix5系:対象をVueに絞った場合

Node12 + Vue Node18 + Vue
ビルド時間 6.916秒 3.802秒

Vue単体ではそこまで時間がかかっていないので、SCSSのトランスパイルがボトルネックになっているようでした。 このままでは流石に開発効率に影響する速度です。。

対応したこと

対応の選択肢としては下記がありましたが

  • Laravel Mix5→6系に更新しwebpackの設定をチューニングする
  • Viteに変更する

Laravelを利用したプロジェクトも多数あるため、Laravel Mix→Viteへの移行の検証を行いたいという理由でLaravel MixからViteへの変更を行いました。

laravel-vite-pluginも提供されていますが、今回対象になっているリポジトリではyii frameworkで構成されているため利用を見送りました。

結果どうなったか?

productionビルドで約6秒と大幅な改善が見られました。

Vite:Node18

Dart sass + Vue Vue
ビルド時間 5.59秒 2.43秒

なぜこの結果になったのか?

  • 複数ファイルから参照されるモジュールは個別のESmodulesとして出力される
    上がLaravel Mixで下がViteの結果です。
    グレーアウトしている部分が多いのでわかりづらいのですが、Vueの依存関係がViteの場合別ファイルにまとまっていることがわかります。

  • CSS圧縮は組み込みサポートされていて、esbuild、terserを選択可能(デフォルトはesbuild。今回は検証不足のためterserを選択)
  • SCSSのトランスパイルについては内部的にsass-loaderを使っているようなので、差分はそれほどなさそう

productionビルドに関してはここまで結果の差が出るとは思っていませんでした。
ビルドに要する時間のみを見ると、SCSS圧縮の部分で大きな改善が見られたので今回の場合Laravel Mixのままでもその部分を見直せば改善できた可能性もあったのかもしれません。

はまりどころ

  • SCSS

元々のディレクトリ構成が複雑なので、トランスパイルしたcssを出力するディレクトリ構成の保持がデフォルト設定では困難でした。提供されている変数では解消できなかったため、Viteの設定ファイルで制御するようにしました。(そもそもトランスパイル後のcssは複雑なディレクトリ構成にしない方が良さそう)

  • Vue・js

    • 出力結果がESmodulesを採用しているため、jsファイルの読み込み方の変更が必要

      ASIS:<script type="text/javascript" src="/js/xxx.js"></script>
      TOBE:<script type="module" src="/js/xxx.js"></script>

      古いブラウザではサポートされていないので注意が必要です。 レガシーブラウザもプラグインでサポート可能ですが、今回の対象ページではサポート外のブラウザの利用率0.13%だったのでレガシー対応はせずに利用しています。

    • ランタイムオンリービルドがデフォルト設定なので完全ビルドの場合はaliasの設定が必要 bladeからpropsをわたしているケースで思うようにVueテンプレートに値がわたっていなかったのですが、Laravel Mixの場合はaliasの設定は不要で、意識せずに解決されていた部分だったのでパッとわからずはまってしまいました。(おそらく依存関係にvue-loaderが含まれていたので意識せず解決してくれてた可能性が高い)


      (引用: インストール — Vue.js )

    • require()が使えない ViteはESmodulesによって動作しているので、requireは変換されない。requireはCommonJSの仕様でブラウザでは読むことができないのでエラーとなります。 そのため今までrequireで読み込んでいた部分はimportへの書き換えが必要になります。

まとめ

  • ビルドが爆速に
  • cssをgit管理しているが故の手順が一つ削減
    • トランスパイル後のcssをgit管理しているためlocalでの ビルドが必須だが、重すぎて以前は開発中とpush前でビルドの実行コマンドを分けていたが、分ける必要がなくなった(今回の主題からはずれてしまうため記載していませんが、CIも整えたい)
  • Vue3のアップデート対応の準備ができた

上記の内容が改善され、開発効率はとても良くなりました。
部分的にはまりどこともありましたが、今回の場合対象がほぼSCSSでVueファイルの対象が少なかったため移行も比較的簡易に行うことができました。
対象範囲が広い場合は、requireの解消などエラーの解消のために変更が必要になる部分も多く、またファイル分割数など異なる部分も多数あるので充分に検証を行う期間を確保する必要がでてくると感じました。

今回使うことができませんでしたが、開発サーバーを活用した機能は開発体験をさらに良くしてくれそうなので HMRの活用(開発サーバーの起動だけためしたところ700msほどだった)についても今後検討していければと思います。