医師向けSalesforceのGmailへの送信者向けガイドライン対応

エムスリーキャリアの医師戦略推進チームの後藤です。

医師戦略推進チームでは、医師採用担当のコンサルタントが利用するSalesforce(Sales Cloud)の開発・保守・運用を担当しています

弊社のコンサルタントが日々の活動状況を入力するのはもちろん、転職を考えている先生や医療機関の担当者様に向けてSalesforceから、さまざまなマーケティングメールを送信しています。 今回は弊社の医師向けSalesforceで、どのようにGmailガイドラインに対応したかをご紹介します。

前提

Gmailガイドライン

Gmailガイドラインによれば、Gmailに対して1日5,000件以上送信するマーケティングメールには購読解除のリンクを含める必要があります。本文中に購読解除ページへのリンクを含めることや、ワンクリックでの購読解除では要件を満たしたことにはなりません。メールヘッダーに<list-unsubscribe>を含めることが必須の要件となります。

Sales Cloudの対応 状況

Salesforceのサポートにメールヘッダーを含めることが可能か確認したところ、Sales Cloudからメールを送信する際にメールヘッダーに任意の値を追加することはできないと回答を得ました。

また、Sales Cloudではメールヘッダーに<list-unsubscribe>を追加する予定はないとのことです。

データ構造

メール送信のための一時オブジェクトに送信情報を保存し、メールを送信する構造です。一時オブジェクトには、送信元メールアドレス、送信先メールアドレス、件名、本文を保存しています。ただし、すべての項目を保存するわけではなく、処理によっては一部の情報のみを保存しています。担当者または求職者を管理するオブジェクトには、複数選択リストで配信を停止する選択肢を管理しています。

対応前の送信方法

一時オブジェクトの作成方法にはAPEXクラス、レコードトリガーフロー、画面フロー、batchなどがあります。一時オブジェクトが作成されると、レコードトリガーフローが起動してSalesforceからメールを送信します。

対応方針

購読解除に対応するために送信数や料金を加味して検討した結果、弊社ではSendgridからメールを送信することに決定いたしました。また、機会損失を回避するために、送信するメールの種類ごとに配信を停止する選択肢を提供することとしました。

対象範囲

Salesforceから送信しているメールのうち、マーケティングメールと判断されるメールを対象とします。Googleから明確な基準がないため、あくまで社内の判断で行います。チームの判断基準としては以下のとおりです。

  • 複数人に対して同時に送信する
  • 求人や求職者の情報を案内している

送信処理

一時オブジェクト作成時に起動するAPEXトリガーを作成し、Sendgridにメールを送信します。 マーケティングメール以外でも一時オブジェクトを利用しているためカスタムメタデータ型で、送信の可否を管理できるように対応しました。 ヘッダーに購読解除用のリクエストURLを付与しました。URLから解除の対象者と機能を特定できるようにしました。

送信処理

ハマったポイント1:非同期処理の制限を回避する必要がある

Salesforceから外部にコールアウトをするには非同期で実装する必要があります。 さらに、1トランザクションで呼び出し可能なコールアウト数は100回までとなっており、1回の送信件数が少ない処理では特に問題はありませんでしたが、batchで大量送信する機能では通常利用では実用に耐えられません。 回避方法として、レコードを100レコードごとに送信するようにしました。

ハマったポイント2:batchから非同期処理(future )を呼び出せない

非同期処理からfutureアノテーションが付いたメソッドを呼び出すことはできません。 batchも非同期処理の一種になりますので、futureメソッドを呼び出そうとすると制限エラーが返されます。 futureメソッドの代わりにqueueableを継承したクラスを定義して、Database.AllowsCalloutsを付けることで回避可能です。

購読解除

エンドユーザーが購読解除リンクを押した時に、送信時に付与した購読解除用のURLにリクエストを送信します。 リクエスト先は弊社のAWSのLamdaとなっており、種別と対象者をDynamoDBに保存します。 ETLサービスのTroccoで定期的にDynamoDBからSalesforceの購読解除用の一時オブジェクトに連携します。 購読解除用の一時オブジェクトが作成された後は、レコードトリガーフローで解除対象のオブジェクトを更新して以後メールが送信されない仕組みとなっています。

購読解除

最後に

Googleから明確な基準が示されない中で、手探りながらもビジネス側の要件を満たし、かつ、送信と購読解除ともに共通処理化をすることで今後の開発負担も軽減することが可能な作りにすることができました。 また、現場の使用感を変えることなく、リリース後に問題を発生させなかった点もよかったと思っています。

エンジニア組織内の共同プロジェクト

今回は近藤(a-kondo)からエンジニア組織内で進めている共同プロジェクトについてご紹介させて頂きます。

エンジニア組織の現状

 私たち、エムスリーキャリアでは、人数が増えて行く中でエンジニア組織は55名を超える組織となりました。

 当社のエンジニア組織は開発チームは3つに分離しています。下記の図では「Web」、「新規サービス」、「戦略推進」と記載している箇所です。

 一方で、当社では事業を横断して、会社全体としてサービスを横断して提供して行こうということに取り組んでいます。エンジニア組織でもその課題に向けて歩みを進めています。

 その取り組みの1つが共同プロジェクトです。

 


  

共同プロジェクトの全体像

共同プロジェクトしては9つのプロジェクトを動かしています。先ずはそのうちの7つを、目的/内容について、ご紹介したいと思います。

  • Chat GPT 
    • 目的:ChatGPTの社内導入、活用促進
    • 内容:社内の有志を集めて、様々なユースケースでの事例を作り上げています。社内業務効率化案件が多いですが、ChatGPTを用いてユーザーの方の操作をサポートする機能のリリースに繋がっています。

  •  開発標準化
    • 目的:セキュリティ対応、Docker等の開発環境整備等で、チーム間の横断的な対応サポート
    • 内容:定例としては四半期ごとに、その他トピックがあれば随時、対応に関する意見交換、指針決め、作業分担を行なっています。
  •  UI/UX
    •  目的:フロント技術選定や、デザイナーと協業方法の整理等を通じてのプロダクトのU I/UX体験の向上
    • 内容:Vue.js/Hotwire等のフロント技術選定、バージョンアップ方式選定、フロント/バックエンドとの責務の整理、デザインシステムの策定サポート等に取り組んでいます。
  •  SRE 
    • 目的:インフラ関連のセキュリティ担保、監視・運用の向上
    • 内容:クラウド運用におけるセキュリティポリシー策定、実行等をインフラチームを中心に進めています。
  •  PdM / BDE(BusinessDevelopmentEngineering)
    • 目的:当社では年間10近い新規事業を立ち上げ、立ち上げ前のテスト検証を行なっています。そのシステム面でのサポートを推進
    • 内容:全社的にPdMというポジションを設置しています。エンジニアリング組織の中では、特に、0→1といった新規事業を進めるために、BDEという役割/チームを置いています。そのチーム以外でも横断的に分担しながら新規事業を進めています。
  •  人材教育
    • 目的:エンジニアとしてのハード面、ソフト面でのスキルアップ促進
    • 内容:
      • ハード面:アーキの会、テスト技術、AWS/GCP に関するセミナー受講 オブジェクト指向を学ぶための輪読、等               
      • ソフト面:ソフトスキル、特に最近だと調整力を意識しています。現場でのMTGに同席した結果をエンジニアリングGに持ち帰って共有するといったことも併せて行なっています。
  •  Techblog
    • 目的:エンジニア組織にノウハウを蓄積すること、社外へのプレゼンスを高めて技術広報のツールとして機能させること
    • 内容:こちらのTechblogです。月2回の更新を目指しています。

具体例 1.共通基盤、2.データ基盤

残り、2つの共通プロジェクトについてはより具体的にお伝えさせて頂きます。

  1. 共通基盤
    • 目的:当社はこれまで事業ごとに、Ruby OnRailsを技術選定時に選択することで迅速なサービス立ち上げを行なって来ました。ここ数年では会社の事業規模も大きくなり、会社全体で当社の様々なサービスをお客様に届けることを目標としています。システム面でも共通基盤の考え方を取り入れることでシームレスなサービス提供を目指しています。

    •  

      内容:

      • アーキテクチャのグランドデザイン策定
        • その目的のために昨年定めたのがグランドデザインです。考え方としては、サービス層 - データ連携層 - データ層といったレイヤーごとの責務を整理しています。デジタル庁のグランドデザインを参考にさせて頂きました。
      • アーキの会による情報共有
        • グランドデザインに沿ったシステム構成変更にいくつか取り組んでいます。その情報共有を行う場として、アーキテクチャーを考える会(通称:アーキの会)を月1回実施しています。前々回は、モジューラモノリス、前回はフロント - バックエンドの責務分担等をテーマに掲げました。
  2.  データ基盤
    • 目的:グランドデザインに沿ったデータ基盤を構築して、運用すること

    • 内容:Modern Data Stackの考え方に沿って、データ基盤を昨年から再構築しました。Lake - DWH - DataMart層に沿って、BigQuery / trocco / dbtといった技術で構築しています。現在はデータ活用の促進というフェーズに移っています。

最後に

現在、私たちの組織では絶賛エンジニア採用を進めています。

上記の取り組みに関心を持って頂いた方で詳しく話を聞いてみたいという方がいらっしゃいましたら、カジュアル面談も受け付けておりますので、お話しさせて頂ければ嬉しいです。

career.m3career.com

 

 

Helperファイルを作成してPlaywrightのE2Eテストを実行してみた

エムスリーキャリアでQAを担当している川浪です。

本記事ではPlaywrightでHelperファイルを作成してE2Eテストを実行する方法をご紹介します。*1

本記事の前提条件

本記事の前提条件は以下の通りです。

Helperファイルとは?

Helperファイルは、テストケースでよく使う共通の処理や操作をまとめておくファイルのことです。

フォームの入力や特定のページへの移動など、何度も使う処理をHelperファイルに書いておくことで、テストコードの再利用性や保守性を向上することができます。

今回は、例としてログイン操作のHelperファイルを作成しテストを実行する方法を説明します。

 

下図のようにログインフォームで入力したユーザー名が表示される簡単なアプリケーションを用意します。

ログインページのHTML

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="UTF-8">
      <title>login sample</title>
      <link rel="stylesheet" href="css/style.css" type="text/css">
    </head>
    <body>
      <form method="POST" action="/login">
      <div>username<input type="text" name="username"></div>
      <div>password<input type="password" name="password"></div>
      <div><input type="submit" name="login" value="ログイン"></div>
      </form>
    </body>
    </html>

Helperファイルの作成

まず、Playwrightのプロジェクトフォルダ直下にHelpersフォルダを作成し、作成したフォルダに「loginHelper.ts」というHelperファイルを作成します。

Helperファイルに「login」という名称でログイン操作のヘルパー関数を以下のとおり記述します。

import { Page } from '@playwright/test';

export async function login(page: Page, userName: string, password: string) {
  await page.locator('input[name="username"]').fill(userName);
  await page.locator('input[name="password"]').fill(password);
  await page.getByRole('button', { name: 'Submit' }).click();
}
  • 非同期関数(async function)として宣言
  • PlaywrightのPageオブジェクトをヘルパー関数の引数で渡す
  • アサーションはヘルパー関数には記述しない(specファイルに記述する)

specファイルの作成

次にtestsフォルダに「logintest.spec.ts」という名称のspecファイル(テストの詳細を記述するファイル)を作成します。

specファイルには、Playwrightのtest関数を記述します。

import { test, expect } from '@playwright/test';
import { login } from '../helpers/loginHelper';

test('ログイン操作のテスト', async ({ page }) => {
  const username: string = 'QATester';
  const password: string = 'password';
  
  await page.goto( 'http://localhost:3000/login' );
  await login(page, username, password);
  
  // ログイン後、bodyタグにログインユーザー名が含まれていることを確認
  const bodyText = await page.innerText('body');
  expect(bodyText).toBe(`Hello ${username}!!`);
});
  • Helperファイルに追加した関数「login」をインポート
  • test関数の中でログイン操作とアサーションのコードを記述

specファイル作成後、VS Code のサイドバーから「Testing」アイコンを選択します。

表示されるTest Explorerからテストを実行することができます。

まとめ

ログイン操作という簡単な事例でしたが、Helpersファイルを利用したE2Eテストを実行することができました。

ページオブジェクトモデル(Page Object Model)よりも学習コストの少ないHelpersファイルでの運用もこれから検討していきたいと思います。

 

*1:Helpersファイルに関してPlaywrightの公式ドキュメントに記載はなく、同じE2EテストフレームワークであるTestCafeの「Create Helpers」を参考にしました

レガシーなRailsアプリケーションのアップグレードをどう進めたか

こんにちは。エムスリーキャリアでエンジニアをしているakitoshigaです。

まだリリース前ではありますが、直近でレガシーなRailsアプリのアップグレードを実施したのでそのことについて紹介します。

 

弊社には約10年前にRailsで構築されたメディアサーバーが存在しています。

このメディアサーバはWebAPIによって画像ファイルやドキュメントファイルのアップロード・ダウンロードが行えるようなシンプルなもので特定のサービスにおける社内・社外のファイル共有のために使用されていました。

アップグレード前はそれぞれ以下のバージョンでした。

過去に一度アップグレードを施されたものの、以降一度もアップグレードがなされていないような状況でした。

最近このメディアサーバーを社内の他のサービスでも使用したいと考えらえるようになり、それを機に今回アップグレードに至りました。

アップグレード後のバージョンはそれぞれ以下です。

Railsにいたってはメジャーバージョンを2つ上げる大幅なアップグレードを実施しました。

 

アップグレードの流れ

Railsガイドのアップグレードガイドを参考にしつつも、以下のようにしました。

1. Gemのアップグレード

2. Railsを6.1.0にアップグレード

3. Rubyを3.3.1にアップグレード

4. Railsを7.1.3にアップグレード

5. Gemのアップグレード

 

本来であればもっと細かい粒度でインクリメンタルにアップグレードを行うべきですが、Railsはバージョン6を挟んで2回のアップグレード、Rubyは1回のアップグレードで目標バージョンに到達させました。

 

このようにした理由としては以下です。

  • 小規模なシステム(モデル数9個)であり機能がシンプルでデバッグが比較的容易だった
  • リリースノートを確認したところクリティカルに影響する変更がなかった
  • 後述のnew_framework_defaults_*.rbはメジャーバージョン事に対応したかった
  • あまり時間がなかった...

 

以下で詳しく解説します。

 

1. Gemのアップグレード

まず最初に現状のGemを精査して使われていないものは削除しました。

その上で現状のバージョンで導入できるもっとも最新のGemにアップグレードしました。

デバッグを行い現状のRailsRubyに対応していないGemはバージョンを戻して固定しました。

バージョンを固定したGemは後の工程で最新にします。

 

2. Railsを6.1.0にアップグレード

Gemfileのrailsのバージョンを6.1.0に固定してbundle update railsを実行。

その後bundle exec rails app:updateを実行しました。

対話形式で各種設定ファイルを上書きするかそのままにするかを設定しますが、以下のようにしました

  • 一度すべての設定ファイルを上書きする
  • git diffで差分を見て、過去手動で設定した部分をマージしていく

lazygitは行単位で変更を取り消せるのでこの作業を行うのに便利でした

www.fastruby.io

 

bundle exec rails app:updateを行うとconfig/initializers配下にnew_frame_work_defaults_*.rbが生成されます。

これはRailsのマイナーバージョン以上をアップグレードするたびに生成されるファイルで、Railsのデフォルトの設定の更新差分が記載されています。

*の部分はアップグレードされたときのバージョンが入るので今回はnew_frame_work_defaults_6_1.rbとなります

生成された直後はコメントアウトされており、コメントを解除していくことで設定が適用されていきます。

ただし、これらの設定をすべて適用しても良い場合はconfig/application.rbの項目

config.load_defaultsの設定値をアップグレードしたバージョンに指定すればnew_frame_work_defaults_*.rbをすべてコメントアウトしたのと同じ状態

になります。

new_frame_work_defaults_*.rbを個別で管理する必要はないので以下のようにしました。

1. インクリメンタルにコメントを外していく

2. 影響のあるものはconfig/application.rbや他の設定ファイルに記載

3. config.load_defaultsの値を変更(今回は 6.1)

4. new_frame_work_defaults_*.rbを削除

 

3. Rubyを3.3.1にアップグレード

開発環境のDockerfileで定義されているRubyのバージョンを3.3.1に変更しました。

このタイミングでbundlerもアップグレードしました。

アップグレードしたbundlerでGemfile.lockを出力する必要があるので以下を実施しました。

bundler update --bundler

幸いバグらしいバグが出なかったのですぐに完了しました。

 

4. Railsを7.1.3にアップグレード

6.1.0にアップグレードした時と同様の流れでアップグレードを実施しました。

さすがにメジャーバージョンを2つ上げると使用していたGemが現在のバージョンに対応できなくなったりDeprecatedの警告が多くなってきます。

使用できなくなったGemや、警告されている部分の対応を行いました。

 

5. Gemのアップグレード

バージョンを固定していたGemを最新に変更しました。

 

発生したエラーとその解決

他の大規模なRailsアプリに対してアップグレードは比較的容易だったとはいえRailsやGemの依存関係に起因するエラーはかなり複雑でした。

多くのエラーは先人がGitHubのIssueやブログにまとめたりしてくれていますが、そうでない物はGemをcloneして特定のメソッドに対してバージョンごとに差分を確認していくような作業も行いました。

 

まとめ

アップグレードはこまめにやったほうが良いとは思うものの、品質の向上・担保における取り組みはプロダクトのフェーズによってはどうしても後回しになってしまいがちだと感じています。

定期的にアップグレードを行えるような仕組みづくりの重要さを実感しました。

Railsの型チェッカーツールSorbetを試験導入しました。

こんにちは、エムスリーキャリアでエンジニアをしているakitoshigaです。

前回書いた『Ruby on Railsのモジュラーモノリス化 ~PackwerkとPacksRailsの導入~ 』に関連する施策のひとつとして、静的型解析のSorbetとTapiocaを試験導入した話をご紹介します。

SorbetとTapiocaについて

Sorbetとは、Stripeが開発したRubyの静的(漸進的)型チェッカーです。

sorbet.org

 

SorbetはRBIファイルとRubyファイルへの「sigil(s)」の記載によって機能するのですが、そのRBIファイルの作成をサポートするのがTapiocaです。

github.com

ちなみにTapiocaはShopify製になります。

なぜ導入したのか

弊社で保有するプロダクトの1つであるM3Career Primeではモジュラーモノリス化に取り組んでおり、この推進をするために導入したのが主な理由です。

具体的には以下の効果を見込んでいます。

型・インターフェースによるサポート

モジュラーモノリス化のためには当然ですがコードのモジュール化を行う必要があります。

M3Career Primeはいわゆる「巨大な泥団子」状態となっており、この状態からコードの境界を見極めAPIの定義・カプセル化を行っていくには型とインターフェースによるサポートが有効だと判断しました。

TechRachoさんの以下の記事にある『静的型が有効な場合とは』にそのまま当てはまる形です。

techracho.bpsinc.jp

 

また、 インクリメンタルに導入が可能で途中からやめようと思えばやめられる点もあり今回導入に至りました。

現状の運用

まだ試験運用中ということもあり、TapiocaでRBIを自動生成した後は新規追加するAPIにsigilを随時定義しているような形で進めています。

既存のコードへの型定義は行っておりません。

 

また、Sorbetには適用する制約のレベルを段階的に設定できますが他チームメンバー内で相談して以下のようにしました。

  • 制約レベルは `typed: true`
  • パブリックなAPIには必ずsigilを記載
  • 他の箇所は任意とする

ただしこのルールは暫定的なものでSorbetのもたらす恩恵が大きいと感じた場合はsigilの制約のレベルを強くするなど運用を変えていく可能性があります。

 

Steep(RBS)との比較

Sorbet以外の同じ型チェッカーで有名なSteepがありますが、以下の理由でSorbetを選択しました。

  •  Sorbetの方が型を制約するレベルを柔軟に設定できる。
  •  Sorbetはランタイムで型のチェックができる

SorbetとSteepの比較についてはWantedlyさんのテックブログで詳しくまとめてくださっています。

sg.wantedly.com

 

しかし、今後もずっとSorbetを使い続けるという保証はありません。

理由は以下で説明します。

Rubyの型の動向

以下でまつもとゆきひろさんが言及されているように、Rubyのそもそものコンセプトとして静的な型の定義は不要としています。

jp.quora.com

しかし、Rubyプログラマーの間で型に対する需要があるというのも事実で、そんな中で今年開催RubyKaigiでまつもとゆきひろさんが型について言及する場面がありました。

 

またフルタイムRubyコミッターでSteepの開発者のsoutaroさんもコメントでRBSを定義できるGemを出していますね。

github.com

 

他にもaws-sdk-ruby配下のすべてのgemにRBSが含まれるようになったというニュースもあり、RBSはかなり盛り上がっているなと感じています。

まとめ

RBSを使用した型チェッカーに優位性があると判断した場合は、Steepや他の型チェッカーに移行する可能性もあるので今後の動向に注目していきたいと思います。

 

ドキュメント化のススメ - ドキュメント作成が苦手なアナタに

エムスリーキャリアでWebエンジニアやっている諸岡(morooka_cube)と申します。現在は薬局向けBtoBサービスのリニューアル案件に携わっています。

先日、開発ツールのレビューサイトFindy Toolsにて、データ基盤構築ツールTROCCOの記事を寄稿しました。

最近のマイトレンドはHotwireとdbtとショッピングモール巡りです。

休日のプライベートな作業や情報収集する時、自宅だと捗らないという方いませんか?そんな時の気分転換にショッピングモール巡りがおすすめです!

スタバでマック

(このブログもショッピングモール巡りがてら「スタバでマック」スタイルで書いてます)

 

ドキュメント化に取り組む以前の状況

私自身、ドキュメント化に対しては消極的な姿勢でした。

  • 実装スピードに自信があり、かつドキュメント化は面倒で時間のかかる作業と思い込んで相対的にドキュメントを軽視していた
  • Word・Excelで書かれた網羅的なドキュメントに対するアレルギー反応
  • ドキュメントが効果的に働いているプロジェクトに関わったことがなかった

等が要因として挙げられます。要するに私もドキュメント作成が苦手です!!!

そして現在担当しているサービス自体もこのような状況だったので、リニューアル案件を進めるにあたり以下の課題が発生していました。

  • ビジネスロジックのあいまい化・複雑化
    • 設計・実装の前提となるロジックが明確になっていない
    • コードリーディングしたり本番環境を動かして理解する必要あり
    • このような状態で追加改修をミルフィーユのように積み上げてきたので、リファクタリングしようにも「触らぬ神クラスに祟りなし」状態
  • 関係者間のコミュニケーションコスト増加
    • リニューアル案件に際しビジネスサイド・エンジニアともに関係者を増員
    • 複雑なビジネスロジックのキャッチアップに追われる
    • 既存メンバーであっても誤解や要件漏れを起こすため、コミュニケーションの齟齬原因に
  • 要件定義・仕様設計の手戻り
    • 現状仕様の理解が浅い・共通認識が取れていない状態で要件定義・仕様設計
    • 実装フェーズに入ってようやく考慮漏れに気付き、要件定義のやり直し
    • 最悪のケースとして「これは特殊パターンだから設計変更ではなくコーディングの工夫で乗り切ろう」でバグの温床
    • 既存機能に関しても穴が見つかり、「スコープ広げてイチから再設計したほうがいいのでは?」なんてことも

ドキュメント化に向き合ってみて得られたこと

ドキュメント手法に対する「食わず嫌い」状態から、見様見真似でやってみたところ以下のような効果が得られました。

  • 関係者間コミュニケーションの改善
    • チーム内や関係者間のコミュニケーションがスムーズに
    • 要件や仕様の誤解防止
  • 要件定義の進捗改善
    • 「ここの要件は記入まだ・MTGで詰める」等メモを残すことで進捗の見える化・考慮漏れの防止
    • 意思決定の優先順位が明確に
  • ビジネスロジックの解像度向上・簡素化
    • 手始めに現行機能のロジックや業務フローを文書化してから「どのように追加するのがベストか」ベースで検討
    • ロジック・業務フローの複雑化を防止
    • 検討した結果既存ロジック・業務フローに変更を加えることになっても、関係者への周知が簡単に

ドキュメント化のフレームワーク・ベストプラクティス

アジャイルソフトウェア開発宣言包括的なドキュメントよりも動くソフトウェア

アジャイルソフトウェア開発宣言

アジャイルソフトウェア開発宣言

はじめてこの文書を読んだ時、私は「なるほど、ドキュメントも大事だけど動くソフトウェアのほうが大事なんだな。ドキュメント化には消極的な姿勢のままで問題ないか」程度の浅い理解でした。

今は別の視点で解釈しています。

包括的なドキュメント」とは読み手の対象(経営層だったり新人プログラマーだったり)に関わらず理解できるよう情報が網羅された文書のことであり、関係者とのアジャイルなコミュニケーションができているのであれば、読み手の対象を絞った上で包括性を欠いてもよいと理解しました。

そして、アジャイルコミュニケーションの外野にいるステークホルダーに対しては、ドキュメントの納入ではなく「動くソフトウェア」を開発進捗のエビデンスとするという価値観です。

ドキュメントの網羅性は関係者とのコミュニケーション密度によって変わる

上記アジャイル開発宣言の解釈を前提とすると、「アジャイルなコミュニケーション」の実現具合によってドキュメントの適切な網羅性が変わることになります。

ビジネスサイドとの関係性ができていないプロジェクト初期は「言った・言ってない」を文書化する作業に追われるかもしれないし、逆に全ての意思決定を対面会話で済ませるほど密結合にコミュニケーションしているなら、会話の結論をメモするだけで済むかもしれません。

つまり、「ドキュメントのフォーマットを固定化するのではなく、コミュニケーション密度に応じてフォーマットを柔軟に変える」という考え方です。

状態遷移図・状態遷移表

ここまでマインドの話中心になってしまいました🙇‍♂️具体的な方法論も書きます!

先日社内のQAグループ主導でソフトウェアテスト手法の講座があり、その題材がソフトウェア設計・ドキュメント化の観点からもとても参考になったのでシェアします。

状態遷移図を書くと、「状態」「トリガー(イベント)」で考慮漏れや不整合がないか整理することができます。
また、「遷移前の状態」「トリガー」「遷移後の状態」の関係を表した状態遷移表を書くことで、あいまいな仕様や認識の齟齬を生みやすい箇所を特定することができます。

実際のシステムに適応した例

講座の中では、この状態遷移図・遷移表に以下機能を追加する演習を行いました。

「承認済み」を「再編集」することで「未申請」にすることができる
「承認済み」を再編集で「未申請」にした場合のみ以下の動作とする
 ・「取り消し」で「承認済み」に戻る
 ・「申請中」に進んだ後も「未申請」に戻れば「取り消し」可能
 ・「取り消し」後の申請内容は再編集前の状態に戻す

…文章のみだとなんだかよくわからない印象(=ビジネスロジックの解像度が低い)ですが、状態遷移図に起こすことで、「再編集」「取り消し」というトリガーを実現するために「再編集・未申請」「再編集・申請中」という新たな状態が必要になることがわかります。

「再編集・未申請」の場合は取り消し可だが、再編集ではない「未申請」の場合は取り消し不可とするため)

「再編集」「取り消し」を追加した状態遷移図

「再編集」「取り消し」を追加した状態遷移表

システム間連携時のフローチャート

システム間のデータ連携を行う機能を開発する際は、

  • 私「処理Aは対向システムがやると思ってた…」
  • 対向システム担当「処理Aはそちらがやると思ってた…」

のような認識齟齬を防ぐため、対向システムとの責務分けを明確にする必要があります。

そんな時はフローチャートを書いて「この処理は対向システムの責務」と明記するとわかりやすいです。

システム間連携時のフローチャート

生成AIの活用(情報求ム)

フレームワーク・ベストプラクティスを駆使しても、ドキュメント化は時間がかかります。

大枠を自分でプロットした上で、面倒な作業は生成AIにお任せできるといいのですが…このあたり私はまだ試せていないので、情報提供お待ちしています!

終わりに

ドキュメント化、こわくないよ!!

PlaywrightでのE2Eテストで選択できるモバイルブラウザについて

エムスリーキャリアでQAを担当している川浪です。

私は現在、医師と薬剤師向けのWebアプリケーションを提供するプロジェクトにおいてQAとして活動しています。

タイトルにもあるように、本記事ではPlaywrightでテスト実行する際に選択できるモバイルブラウザの追加方法についてご紹介します。

Playwrightとは

Playwrightは、マイクロソフトが開発・提供しているE2Eテスト自動化フレームワークです。  
https://playwright.dev/

詳細な説明は割愛しますが、Visual Studio CodeVSCode)の機能拡張(Playwright Test for VS Code)も提供されており、VSCode上でPlaywrightのスクリプトを作成・実行することができます。

 

本記事の前提条件

本記事の前提条件は以下の通りです。

 

Playwrightで動作確認できるブラウザ

Playwrightをインストールすると、以下のブラウザで動作確認ができます。

上記ブラウザはいずれもPCのブラウザとして動作するので、Playwrightの初期状態ではモバイルのブラウザで動作確認ができません。

モバイルデバイスエミュレーターでテストするには

モバイルのブラウザ(iOSSafariAndroidChrome)で動作確認するには、playwright.config.ts を開いて編集します*1

playwright.config.ts の初期状態では、以下の通りモバイルのブラウザに関してはコメントアウトされているので、コメント解除すれば利用できるようになります

    /* Test against mobile viewports. */
    // {
    //   name: 'Mobile Chrome',
    //   use: { ...devices['Pixel 5'] },
    // },
    // {
    //   name: 'Mobile Safari',
    //   use: { ...devices['iPhone 12'] },
    // },

VSCodeで選択項目に追加されていることが確認できます

 

エミュレーターの種類を増やすには?

モバイルデバイスでのE2Eテストが可能になりましたが、モバイル版ChromeはPixel 5、モバイル版SafariiPhone 12 とそれほど新しいデバイスではありません(2024年4月時点)

他にエミュレートできるブラウザはないのか?と思い調べてみると、モバイルデバイスエミュレーターは、以下のファイルで定義されていました

(Playwrightのインストールフォルダ)\node_modules\playwright-core\lib\server\deviceDescriptorsSource.json

jsonファイルを開いてみると、ポートレートモード(縦向き)とランドスケープモード(横向き)の両方が定義されているデバイスもあります

deviceDescriptorsSource.json を参照し、追加したいデバイスのキーをplaywright.config.ts に追記すれば、コメントアウト解除した以外のデバイスでも動作確認が可能です

例えば、iPhone 14 Pro を追加したい場合は下記のように追記します

    /* Test against mobile viewports. */
    {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 5'] },
    },
    {
      name: 'Mobile Safari',
      use: { ...devices['iPhone 12'] },
    },
    {
      name: 'Mobile Safari on iPhone 14 Pro',
      use: { ...devices['iPhone 14 Pro'] },
    },

おわりに

今回はPlaywrightでモバイルデバイスでのテスト実行についてご紹介しました。

Playwrightは、CypressやTestCafeといった先行リリースされたE2Eテストのフレームワークと比べ、動作確認できるエミュレーターの多さという意味でも利用価値が高いと考えています。

弊社のサイトはスマートフォンでの操作を前提としたWebアプリケーションが多いので、今後のQA業務でテストを自動化する際にPlaywrightの利用も視野に入れていきたいと思います。

 

*1:playwright.config.tsファイルは、Playwrightのインストール先フォルダ直下にあります