AWS AppSyncについて勉強してみた

こんにちは、弥生の八木です。

この記事は、Misoca+弥生+ALTOA Advent Calendar 2018の 22日目の記事です。

記事を書くにあたって、せっかくなので業務とは関係なく、気になる技術を勉強しようと思ったので、 今回は、AWS AppSyncとそのバックグラウンドの技術であるGraphQLを勉強したことや簡単に作ってみたものについて書きます。

AWS AppSyncとは

GraphQLベースのAPIを作成でき、APIに合わせてDynamoDBを自動で作成できる「フルマネージドGraphQLサービス」です。 AWSのコンソール画面からDBを設計、設定をするだけで簡単にAPIとDBを作成できます。

GraphQLとは

GraphQLは、Facebookにより開発されたオープンソースのクエリ言語のことです。 クエリ言語とは「問い合わせ言語」といい、コンピュータのデータに対して問い合わせるための言語で、代表的なクエリ言語だと、SQLが当てはまります。

以下のようなリクエスト、レスポンスになります。

リクエストサンプル

query list {
  listHoge {
    items {
      id  hoge
    }
  }
}

レスポンスサンプル

{
  "data": {
    listHoge": {
      "items": [
        {
          "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
          "hoge": "hogehoge"
        }
      ]
    }
  }
}

実際に動かしてみた

やること

AWS AppSyncでAPIを作成し、クライアントからAPIにリクエストして、なんでもいいから結果を受け取って「AppSync使ってるぜ」感を味わう!

やったこと

  1. WebクライアントからAWS AppSyncにアクセスできるようにする
  2. AWS AppSyncでAPIとDBを作る
  3. 作成したAPIのエンドポイントなど設定する
  4. WebクライアントからAPIにアクセスし、レスポンス結果を画面に表示する

APIとDBの作り方

  1. AWSコンソールにログインし、「Create API」ボタンをクリックする f:id:ym_AdventC:20181218183733p:plain

  2. 「Create with wizard」にチェックを入れ、「Start」ボタンをクリックする f:id:ym_AdventC:20181218183842p:plain

  3. 「Model Name」に任意にDBの名称を付けて、「Configure model fields」でDBのカラムの設定をする、完了したら「Create」ボタンをクリックする f:id:ym_AdventC:20181218184133p:plain

  4. 「API Name」に任意にAPIの名称を付けて、「Create」ボタンをクリックして完了です f:id:ym_AdventC:20181218184716p:plain

作成したAPIは、AWSコンソール上でも動作させることができます

登録のクエリ f:id:ym_AdventC:20181218192142p:plain

取得のクエリ f:id:ym_AdventC:20181218192344p:plain

APIにアクセスして結果を取得

簡単にReactのサンプルプロジェクトをいじって取得した内容を表示させます。

Reactプロジェクト内のApp.jsの設定にGraphQLのクエリを記述し、レスポンス結果を取得する関数を作成

~~略~~

const ListTodos = `
query list{
  listTodos{
    items{
      id name description
    }
  }
}
`;

class App extends Component {
  state = {todos: []}
  async componentDidMount() {

    const todos = await API.graphql(graphqlOperation(ListTodos))
    console.log('todos:', todos)
    this.setState({todos: todos.data.listTodos.items})
  }

~~略~~

実際にWebブラウザからAPIにアクセス f:id:ym_AdventC:20181219180840p:plain

GraphQL APIでDynamoDBにアクセスして取得したデータを表示しています。 (画面下部のWebブラウザの開発ツールのコンソールに表示しているのが、レスポンス結果です。)

まとめ

AWS AppSyncについて触ってみてわかったこと

  • とても簡単にAPI(GraphQLベース)とDB(DynamoDB)を作成できる
  • APIアプリケーションを作成する必要なし
  • APIサーバーを用意する必要なし
  • DBサーバーを用意する必要なし
  • 簡単なWebアプリやスマホアプリ作成に便利

おわりに

AWS AppSyncで作成したAPIレスポンスを検証するために、React+AWS Amplifyを使用しましたが、環境構築やReactのJSXでWebブラウザ画面に表示するほうが大変でした。。 当たり前ですが、継続的に勉強しなきゃいけませんね!

Misoca+弥生+ALTOA Advent Calendar 2018 、次は@s_nogawaさんの「実践!オブジェクト指向 文系出身ひよっこエンジニアの勉強記」です!お楽しみに!

UWSCでデスクトップアプリの自動テスト

こんにちは。弥生の内山です。
この記事はMisoca+弥生+ALTOA Advent Calendar 2018の21日目の記事です。

はじめに

弥生の主力製品は弥生会計をはじめとしたWindowsアプリです。
弥生ではテストの自動化を進めていますが、結合テスト、統合テストといった工程では、やはり手動でのテストが多く、テストの実施のためにかなりの工数が費やされています。
この工数を少しでも削減しようと、UWSCというツールを使って手動テストを自動化する取り組みを進めてきましたので、その内容をご紹介します。

UWSCとは

UWSCはWindowsの自動操縦ツールです。
20年近く歴史のあるツールで、キーボードやマウスの操作を記録して再生する機能だけでなく、VBA風の独自のスクリプト言語を搭載しており、スクリプトを作成することによってかなり複雑な自動操作を行わせることができます。

やったこと

弥生のWindowsアプリの1つである弥生給与を対象に、手動テストを自動化するための取り組みを進めてきました。
ここでは、具体的にどのようなことを行ってきたかをご紹介します。

まずは1つ自動化してみる

あるテストシナリオに対して、まずはベタにUWSCのスクリプトを書き進めて自動テストができるようにしました。
従来通りのテスト手順書の作成と比較するとかなり時間がかかりましたが、このときは「このテストをどうしても自動化したい」というオーダーを受けていたので、十分に工数を確保することができました。

ライブラリ化する

スクリプトを書き進めていくと、やはり処理を関数などに切り出して整理したくなってきます。
自動化を始めたときから、チームメンバーや他のチームにも展開することを念頭に置いていたので、共通で使えると思った処理は積極的に関数化し、ライブラリとしてまとめていきました。

以下にライブラリを使ったスクリプトの例を示します。

call yayoi-uwsc-lib\kyuyo

事業所データを新規作成する("弥生株式会社", "H3001")

call文は他のUWSCスクリプトファイルを取り込みます。
ここでは、yayoi-uwsc-lib\kyuyo.uwsというスクリプトファイルを読み込んでいます(拡張子は省略可能です)。
このスクリプトファイルがライブラリ本体になります。

「事業所データを新規作成する」は、前述のライブラリに含まれる関数です。
この関数を実行すると、起動している弥生給与の新規作成ウィザードを開き、「弥生株式会社」という事業所名で、導入月度を平成30年1月に設定したデータファイルを作成します。
参考: 給与データの新規作成
弥生給与の新規作成ウィザードは画面数が多く、手動で進めるのは面倒なのですが、この関数はそれを数秒で完了させてくれます。

ここで「え?日本語名の関数…?」と思われた方も多いかもしれません。
ライブラリ中では、関数などの名前に積極的に日本語名を使うようにしました。
理由としては以下です。

  • テスト対象が日本語の製品である: 弥生の製品は基本的に日本国内向けに作られており、画面上に配置される文字列も基本的に日本語です。それらをいちいち英語に翻訳するには時間がかかりますし、訳が適切でないなどの理由で意図が伝わらない可能性も考えられます。そのため、日本語は日本語のまま使った方がよい、という判断をしました。
  • スクリプトを手順書として読めるようにしたい: スクリプトを見た人が、それを手順書として内容を把握できるようにしておきたい、という狙いの他にも、手動テスト用のテスト手順書をベースにスクリプトを作成したとき、スクリプトの内容が手順書と乖離していないことを確認しやすくしたい、と考えました。

テストフレームワークを作成する

ここまでで手動テストをある程度自動化できてきましたが、それを手動テストの代替として使うには、スクリプトがきちんとテストとして振る舞える仕組みが必要だと考えました。
「きちんとテストとして振る舞える」とは、具体的には以下のことだと考えました。

  1. 期待値と実際の値を比較できる
  2. テストの実施結果からレポートを作成できる
  3. 期待通りにテスト対象が動作しなかった場合にテストを終了できる

1は他のプログラミング言語におけるassertのようなものがあればよさそうです。

2は1の結果などを保存しておき、テスト終了時に整形してprintするようにします。
他のプログラミング言語のユニットテストには、結果を詳細に表示しないものもありますが、本件では開発プロセス中のテストフェーズで実施することを想定しているため、実施に関する情報(日時、OS等)も含めてなるべく詳細なレポートを作成するようにします。

3がやや問題で、UWSCではexitexit文を実行するとスクリプトの実行を強制終了させることができるのですが、そうすると2のレポート作成が実行されずに終了してしまうので、テスト実施者は何が起きたのかわからなくなってしまいます。
テストが途中で終了されたらそのことがわかり、レポートも必ず生成されるような仕組みが必要です。

これらの条件を満たすような仕組みを実装していったところ、結果的にテストフレームワークのようなものができあがりました。
このテストフレームワークを使ったスクリプトの例を以下に示します。

// テストフレームワークの読み込み
call yayoi-uwsc-lib\testing

// テスト開始処理
try; try; TEST.START()

// ↓ここからテストスクリプト本体を記述する
TEST.TESTSECTION("テスト1")

dim a = 1
TEST.TESTCASE("テスト1-1", a, 1)
TEST.TESTCASE("テスト1-2", a, 2)
// ↑ここまでテストスクリプト本体を記述する

// テスト終了処理
except; TEST.FAIL(TRY_ERRMSG + " @ " + TRY_ERRLINE); endtry
finally; TEST.END(); endtry

「テスト開始処理」と「テスト終了処理」がだいぶ呪文になっていますが…。
これはUWSCのtry-except構文と、try-finally構文を入れ子にしてあるものを、複文でまとめて書いてあります。
きちんと整形すると、以下のようになります。

try
  try
    TEST.START()
    // テスト本体...
  except
    TEST.FAIL(TRY_ERRMSG + " @ " + TRY_ERRLINE)
  endtry
finally
  TEST.END()
endtry

まずTESTというのが、UWSCのモジュール定義を使って書かれたモジュールです。
UWSCのモジュールは、シングルトン限定のクラスのようなもの、と考えてください。
このTESTモジュールがテストフレームワークの実装になります。

TESTモジュールは以下のような関数を保有しています。

  • START() : テストの開始処理を行う。開始時刻の記録など。
  • END() : テストの終了処理を行う。レポートの出力など。
  • FAIL(エラーメッセージ) : 実行した時点でテストを失敗として強制終了させる
  • TESTCASE(テストケース名, 期待値, 実際の値) : 値の比較を行い、その結果をレポートに追加する。
  • TESTSECTION(セクション名) : 上記TESTCASEをグループ分けする。今のところはレポートの表のヘッダを出力しているだけ…。

テスト本体は、try-excepttry節で実行されます。
これにより、テストの処理中にエラーが発生した場合、except節に飛ばされ、TEST.FAILが実行されます。
TEST.FAILは、テストが失敗であるとレポートに出力するよう設定して、テストを強制終了させます。

外側のtry-finallyは、テストの最後に必ずTEST.ENDを実行させるためのものです。
TEST.ENDは、レポートの出力処理などを行います。
なお、finally節が必ず実行されるように、テストフレームワーク内部ではOPTFINALLYオプションを設定しています。

このような書き方にすることによって、スクリプト終了時に必ずテスト結果のレポート出力が行われるようにしました。
実際に上記のスクリプトを実行すると、UWSCのログウィンドウに以下のようにレポートが出力されます。

UWSCのログウィンドウにレポートのテキストが出力される

レポートのテキストはTracのWiki文法にて整形するようにしてみました。
(弥生ではTracをよく使っています。参考: 6日目の記事
レポートをそのままTracのWikiやチケットにコピペするだけで、テストの実施結果を共有できるようにすることを狙いました。
実際にTracに貼り付けると、以下のようになります。

レポートをTracに貼り付けた様子

テストスクリプトのテンプレートを作成する

これらのライブラリやテストフレームワークを利用してテストを書こう、と思った場合、例えば前述のテストフレームワークの呼び出しなどをゼロから書くのは難しいため、スクリプトを書き始めるためのテンプレートを用意しました。
以下に、テンプレートの抜粋を示します。

//******************************************************************************
// (このスクリプトが何を行うかを説明する)
//******************************************************************************

//==============================================================================
// ライブラリの読み込み
//==============================================================================

call yayoi-uwsc-lib\kyuyo
call yayoi-uwsc-lib\testing

// ↓他にファイルを読み込む場合はここに書く↓


//==============================================================================
// メインスクリプト
//==============================================================================

// テスト開始処理
try; try; TEST.START()

//------------------------------------------------------------------------------
// ↓ここからテストスクリプト本体を記述する↓
//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
// ↑ここまでテストスクリプト本体を記述する↑
//------------------------------------------------------------------------------

// テスト終了処理
except; TEST.FAIL(TRY_ERRMSG + " @ " + TRY_ERRLINE); endtry
finally; TEST.END(); endtry

//==============================================================================
// 関数・モジュール定義
//==============================================================================

// ↓このスクリプトで使う関数やモジュールの定義はここに書く↓

ガイドコメントに従って書いていくことで、ある程度スクリプトを書きやすくすることを狙いました。
ここまでで、他の人がテストを書くために使う道具を準備できました。

チームに展開する

テストをチームメンバーに書いてもらうために、チームに展開する活動を行いました。
具体的には以下のようなことです(といっても最低限やるべきようなことばかりで、特別なことはしていないです)。

  • 作り方を文書化する:テストの書き方や、テストを書いていく上でのノウハウなどを文書にして共有しておく。
  • 説明する: 説明会を開き、上記の文書をもとに、活動の狙いなども含めてチームに説明。
  • サポートする: スクリプトの作成でわからないことや困ったことがあれば、いつでも相談に乗れるようにしておく。

この記事の執筆時点では、チームメンバーがいくつかのテストシナリオについて自動化を進めてくれている…といった状況です。
この取り組みがどれくらいの効果を出せるかは、まだこれからの話になります。

おまけ:UWSCの選定について

UWSCは、現在開発が停止している状態であり、今後のアップデートやサポートは期待できない状況にあります(参考)。
そんな状況で、このままUWSCを使い続けてよいのか? ということについてはかなり悩みました。
結局、以下のような理由で、UWSCを当分は使い続けることにしました。

  • 配布自体は続いているので、現状のまま使い続けることは可能
  • 最悪、乗り換える先がある: 同様の自動操縦ツールにメジャーなものとしてAutoItがあり、これはUWSCでできることはほぼできるので、代替は可能

おわりに

UWSCを使ってテストを自動化する取り組みをご紹介してきました。
もしみなさまの何かの参考になれば幸いです…。

明日は@yusuke_yayoiさんの「AWS AppSyncについて勉強してみた」です。楽しみですね!

AWS ECS+EFSでwordpressサイト構築

こんにちは、弥生の林です。
インフラチームで仕事しています。
この記事はMisoca+弥生+ALTOA Advent Calendar 2018 の19日目の記事です。

告知

本日、弊社弥生のユーザー様に向けて、お役立ちコンテンツを配信するWebサイト  弥報Onlineを公開しました。

media.yayoi-kk.co.jp

従来ありました「弥生マルシェ」からのブランドリニューアルになります。
今回こちらのサイトを、AWSのECS+EFS+wordpressで構成しましたのでご紹介させていただきます。

ECSとEFS

ECSはAWSが提供するコンテナ管理サービスです。コンテナの稼働を監視して必要数を保ってくれたり、 コンテナとALBを紐づける等の仕事をしてくれます。
EFSは複数のEC2からNFSを 利用して、並列アクセスが可能な共有ファイルストレージサービスです。

やったことを簡潔に

1.wordpressの設定ファイルやコンテンツはEFSに、DBデータはAuroraに配置します
2.wordpress用のDockerイメージを作ります
3.Dockerイメージをリポジトリ(ECR)に登録します
4.リポジトリのイメージからECSクラスタ上でコンテナを稼働させます

構成は以下のようになりました。 f:id:ym_AdventC:20181217111552p:plain

なぜEFSを使うのか

wordpressの稼働に必要なデータとして、テーマやプラグイン、コンテンツ、設定ファイル(wp-config.php等)があります。設定ファイルにはデータベースへの接続情報等が書いてあります。
本番運用するにあたって、冗長構成を考えます。1台のホスト(EC2)上で動作している時は問題になりませんが、コンテナが稼働しているホストがスケールした時のことを考えると、追加されたホスト上のコンテナからでも該当のファイル群が参照できるようにしないといけません。
コンテナ間でデータを共有したいという人類の普遍的欲求が生まれます。
どうするか。
高可用性の自前共有ストレージ構築?
うっ、、、あたまが、、、あたまがいたい。

しかし頭痛薬として、今年7月のAWSサミットでEFSが東京リージョンで使えるように*1なったので、気軽に上記のような構成を組むことができるようになりました。
f:id:ym_AdventC:20181217162329p:plain

EFSの使い方

コマンドラインから作成します。

$ aws efs create-file-system --creation-token "TestEFS" --performance-mode generalPurpose --throughput-mode bursting --region  ap-northeast-1
$ aws efs create-mount-target --file-system-id "FileSystemId" --subnet-id "subnet-xxxxxxxx" --security-group "sg-xxxxxxxxxx" --region ap-northeast-1

EC2の起動時にユーザーデータで以下を設定しておくと、どのEC2からでもEFSのデータが参照できるようになります。※AmazonLinux

#!/bin/bash
echo ECS_CLUSTER={ECSクラスタ名} >> /etc/ecs/ecs.config
sudo mkdir /efs
sudo yum install -y amazon-efs-utils
sudo echo {EFSのマウントターゲットID}:/ /efs efs tls,_netdev >> /etc/fstab
sudo mount -a -t efs defaults

ちなみにマウントされたLinux上でのEFSの認識サイズは8エクサバイト。全部埋めると月額250億円ぐらいになるようですね。

$ df -h
fs-xxxxxxx.efs.ap-northeast-1.amazonaws.com:/  8.0E  600M  8.0E   1% /efs

今後の期待とか、やりたいこと

EFSのバックアップ

EFStoEFS BackupというソリューションがAWS公式で紹介されていますが、 構成がトゥーマッチなので、とりあえずEFSマウントしたホストからcpで定期的にバックアップしています。
re:Invent2018で発表されたWindowsからもEFSみたいなの使いたいんやでは標準機能でS3にバックアップできるみたいなので、同じような機能が欲しいですね。

ログ周り

awslogsよりfluentdコンテナをたてて何処かに飛ばしたほうが、cloudwatchlogsに出力するよりお財布に良いと思われるのでそのあたりを改善していきたいです。

次回

@ryotaro_kawakamiさんの記事をお送りします。

ではでは、良いお年をお迎えください。

*1: サミットでもう一つ盛り上がっていたAWS Fargateの東京リージョン対応もアナウンスされていますが、 Fargateは現時点でEFSとの連携がサポートされていないようです。