QUO CARD Digital Innovation Lab Tech Blog

クオカード デジタルイノベーションラボの技術ブログです

クオカードを退職します

こんにちは、デジタルイノベーションラボの飯島です。

この度、2022/9/30 にクオカードを退職することにしました。 理由は転職です。 7 月末に実施された月 1 回のエンジニア全体振り返りでこの話をし、「退職エントリを書いてどこかに投稿しときます」といったところ、ノリと流れと目に見えない力で会社のブログに退職エントリを書くことになりました。

クオカードの良い点も悪い点も書いて欲しいとのことでしたので、それを踏まえて立つ鳥跡を濁さないような内容にしようと思います。

転職の理由

ベンチャー企業で働いてみたかったからです。

クオカードは設立から 30 年以上経っており、会社の制度もしっかり整っていて、もうずっと長く働いている人たちもいます。(かと言って悪しき文化に囚われ続けている訳ではなく、全社で Slack の導入が済んでいたり、コミュニケーションや文書のオープン化などの社内改革も実施されています)

転職先は設立から 2 年ほどしか経過していないので、会社の文化や雰囲気が全く違うんじゃないかな、と思っています。 そういった、今とは全く違う環境で働いてみたい、というのが大きな理由です。

また、バックエンドの開発言語も Kotlin から TypeScript になるので、自分が慣れ親しんだ Kotlin + SpringBoot ではない環境ではコードがどう変わってくるんだろう、という興味もありました。

転職の方針

以下のような方針で探していました。

ベンチャー(曖昧)
フルリモート
残業が無い、もしくは少ない
通話などの同期的な MTG が少ない
静的型付言語を主に使っている
提供しているサービスが面白そう

ちなみに働き方の面に関してクオカードはほぼ満たしています。 通話はもうちょっと少なくなれば良いなあと思っていますが、スクラムを導入しているのでイベントの為に割く時間は必要とも思っています。 参考までに、自分の 1 週間の通話時間はこれくらいです。

月 : 朝会 15 分
火 : 朝会 15 分 / スクラムイベント 約 2 時間 (2週間スプリントなので週ごとに変わる)
水 : 朝会 15 分 + 月末に一回 MTG 1 時間
木 : 朝会 15 分 + リファインメント 1 時間 + アーキテクチャ相談会 1 時間
金 : 朝会 15 分 + 月末に一回 MTG 1 時間

平均すると 1日 40 分ほどでした。

多分ですが、これってかなり短い方だと思うので、もっと短くしたいと言う自分の意見は結構わがままな気もしています。 また、毎週木曜日には外部から講師の方を招いたアーキテクチャ相談会が開催されています。サーバーサイドのアーキテクチャや DB 設計の相談をしてアドバイスをいただいたり、最近のエンジニア界の話題などを解説していただいており、とても参考になっています。 転職することでこの相談会に参加できなくなるのが残念です。

静的型付言語も結構重要なポイントとして見ていました。

あくまで自分の感覚ですが、動的に型付けされる言語だとテストが大変だったりエディタの補完がいまいちなイメージがあります。 そういった言語を触っていると頭がこんがらがってきてしまうので、コンパイラがある言語は必須条件でした。(Rust や Scala で求人を出している会社もあり、すごく魅力的で面談もしていただいたのですが、働き方の面でマッチせず何社か辞退しました。) クオカードはバックエンドに Kotlin、フロントエンドに TypeScript を使っているので、これも良いところだと思っています。

提供しているサービスに関しては、自分が今まで携わったことがないような分野や製品に関わりたいと思っていました。

転職活動

5 ヶ月くらいかけて、いろいろな会社の人に面談や面接をしていただきました。

全部で 10 社くらいだったと思います。

面談前に企業とチャットで会話できるサービスもあり、その段階でマッチするかどうか判断して面談に進まない選択もできたので、最近の転職サービスは凄いな、と思いました。

ここに書いて良いのか分かりませんが、クオカードは割と柔軟に1日の勤怠開始終了時刻を決められるので、8:00 - 16:30 に勤務し、30 分息をついて、17:00 - 18:00 で面談する、といった形で進められました。

転職活動後

ありがたいことに、帰ってきたくなったらいつでも帰ってきて良いよ、と言ってもらえました。

ただ自分は 35 歳までに飯島珈琲店を開くという昔からの夢があるので、もしそうなっていた場合はQUOカードPay 加盟店候補として営業にいくかもしれません。

よろしくお願いします。

あと事務手続き等でお世話になっていた S さんに転職の報告をしたところ、とても暖かい言葉をいただきました。

最後に

クオカードで働いた 3 年間で、エンジニアとして何段階も成長できました。 社内テトリス大会がコロナで開催中止になってしまったこと以外心残りはありません。 ありがとうございました。

AWS WAFをv2へ移行しました

デジタルイノベーションラボのIです。 今回はクオカードペイシステムのAWS WAFをClassicからv2へ移行した件について書こうと思います。

背景

クオカードペイではインフラにAWSを使用しており、外部に公開しているALBにはWAF Classicを適用していました。その名の通りこのWAFは旧世代扱いで、現在ではWAF(v2)の使用が推奨されています。

※ 正確には旧世代のWAFは「AWS WAF Classic」、現世代のWAFは「AWS WAF」という名称なのですが、わかりやすく区別するためにこのエントリでは現世代のWAFをAWSAPIのように「v2」と呼ぶことにします。

botからのアクセスを弾くために、WAF bot controlを使いたいというのが移行を考え始めた直接のきっかけでしたが、更にカスタムレスポンス機能だったり、Log4jの脆弱性に対応したマネージドルールだったり、v2にしかない機能を使いたいというケースが増えてきました。

また今後もWAFの新機能はv2でしか実装されないと思われるため、このままClassicを使用していてはその恩恵も受けられません。

このような経緯でv2への移行を決めました。

移行方法

Classicからv2への移行にはAWS公式の手段が存在します。

—------------------------------------------------------------------------------------------------------------------------

1.自動移行では、既存のウェブ ACL に関連するすべての内容が読み込まれます。AWS WAF Classic で変更または削除される内容はありません。ウェブ ACL とその関連リソースの表現を作成します。この表現は、AWS WAF と互換性があります。新しいウェブ ACLAWS CloudFormation テンプレートを生成し、Amazon S3 バケットに保存します。

2.AWS WAF でウェブ ACL および関連リソースを再作成するために、テンプレートを AWS CloudFormation にデプロイします。

3.ウェブ ACL を確認して手動で移行を完了し、新しいウェブ ACL が最新の AWS WAF の機能を最大限に活用するようにします

4.保護されたリソースを新しいウェブ ACL に手動で切り替えます。

—------------------------------------------------------------------------------------------------------------------------

上記引用の通り、既存のClassic ACLの各種設定をもとに、新規でv2 ACLを作成するCloudFormation stackがデプロイされます。

検証環境で一度実際に試してみた結果、主に以下の理由からこの方法は採用しないことにしました。

  • 結局手動での追加作業が必要な部分が多い
  • 新しく作成されるv2 ACLの名前を指定できない(どうやら、「<移行元Classic ACL名>+<自動で付与されるuuid>」となる様子)
  • そもそもクオカードペイのAWS環境は基本的にTerraformで管理しているため、できるだけCloudFormationでのリソース管理は避けたい

よって、完全に一からv2関連リソースを新規作成することにしました。

ルール設定

移行前のClassicではAWS Marketplaceの「Fortinet Managed Rules for AWS WAF Classic - Complete OWASP Top 10」を利用していました。

v2ではそれに代えて、AWS標準のマネージドルールグループを使うことにしました。WCUを1500以内に収める必要があるため、以下のマネージドルールをACLに追加しました。

—--------------------------------------------------------------------

AWSManagedRulesCommonRuleSet
AWSManagedRulesKnownBadInputsRuleSet
AWSManagedRulesSQLiRuleSet
AWS-AWSManagedRulesLinuxRuleSet
AWS-AWSManagedRulesUnixRuleSet
AWS-AWSManagedRulesAmazonIpReputationList
AWSManagedRulesBotControlRuleSet

計1475WCU

—--------------------------------------------------------------------

また、IPセットも使用してIPアドレスでの制御も実施しました。これはClassicと大差ありません。

チューニング

AWS標準のマネージドルールは特にブラックボックス的なので、実際の動作をみながらのルールのチューニングが必須です。

まずは検証環境に適用し、また本番環境でもルールのアクションを最初はCount状態にして動作確認・ログ分析をしました。WAFのログ出力先はいくつか選択肢がありますが、今回は直接S3に出力してAthenaで分析することにしました。

確認の大きな観点は以下の2点です。

  • 不正なリクエストをブロックできているか
  • 正常なリクエストをブロックしてしまっていないか

WAFに期待しているのは当然前者の機能ですが、ある意味後者の確認のほうがより重要だと思います。正常なユーザアクセスに影響があっては本末転倒です。(実際、検証が不十分でトラブルを起こしてしまいました...)

ブロックの原因となっていたルールをログから特定し、ルールグループから除外しました。

まとめと今後の展望

以上、大まかではありますがWAFの移行に関して実施したことを記載しました。 そもそも移行元のWAF Classicのほうでも沢山のルール設定はしておらず、移行すべきものは少なかったため、実質一から構築したものの作業量はそれほど大きくはなりませんでした。もし複雑なルールを多数設定していたら移行ももっと大変だったと思います。

今後についてですが、現在は正常なリクエストが引っ掛かったルールはルールグループから単純に除外しているのみですが、特にWAF Bot Controlに関してはより細かい制御ができるので時機を見てチューニングをしていきたいです。

15分ルールを導入しました

デジタルイノベーションラボの齋藤です。

以下を参考に15分ルールを導入しました。

https://www.reddit.com/r/MachineLearning/comments/4w6tsv/comment/d6diast/?utm_source=share&utm_medium=web2x&context=3

内容は簡単にまとめると以下のようなものになります。

・何かわからない事があった時、最初の15分間自分で調べる ・もし15分間自分で調べて解決できなかったときは共有用のSlackチャンネルで状況を共有し、他のメンバーにヘルプを依頼する ・共有された問題に知見のあるメンバーがいたらヘルプする

導入の背景

チームで協力して仕事を進める形を目指していますが、他の人にヘルプを求めるのが苦手な人もおり、知見があるメンバーがいてもフォローすることが出来ない状況がありました。またそれによるスケジュール遅延も発生していました。

チームのルールとすることで、他の人にヘルプを求める敷居を下げ、チームで協力して仕事を進められるような形を目指しています。

現状はほぼフルリモートなので、申告が無いとそれぞれの状況が見えにくくなりがちな状況になっています。そのため、早めにアラートが上がる仕組みとしたいと思いました。

質問の仕方

以下のような情報を記載することでヘルプを受けやすくなると考えています。

・背景、文脈を記載する -> 何を実現したいのでその対応をしようとしているのかを記載する

・今までに何をしたか記載 ->どのような試行錯誤を行いどのような結果となったか、その際出力されたログがあればそれも共有する

デジタルイノベーションラボではチームで協力して開発を進めたいエンジニアを募集しています。

QUOカード Digital Innovation Lab.

リモートワークスタイルチェックをやってみました

デジタルイノベーションラボの齋藤です。

永和システムマネジメント アジャイル事業部さんがリモートワークスタイルチェックをやってみたという記事をアップされていました。ミスマッチを防ぐ為に良い取り組みだと思ったので、クオカード デジタルイノベーションラボでもリモートワークスタイルチェックをやってみました。

永和システムマネジメント アジャイル事業部さんの記事

https://blog.agile.esm.co.jp/entry/remote-work-style-check-esm-2022

@mugi_uno さんのリモートワークスタイルチェック

https://gist.github.com/mugi-uno/a794bc199ce7d663f01a434a6e72504c

クオカードでは現在全社的にリモートワークを導入していますが、デジタルイノベーションラボとは少し状況が異なっている為、今回はデジタルイノベーションラボに限った形でチェックをしています。

リモートワーク比重度

リモートワークの導入期間

どの程度リモートワークを導入しているか (≒ 組織としてのリモートワークへの慣れ)

👉「4: 継続してリモートワークを3年以上導入している」

デジタルイノベーションができてからまだ5年経ってないので4になりました。ちなみに設立当初からリモートワークを導入しています。

リモートワークの導入ポリシー

👉「3: 恒久的な導入だが、根本的な制度変更が行われる可能性はある」

設立当初からリモートワーク前提の組織な為おそらく今後リモートワークができなくなる事は無いですが、変更が行われる可能性はゼロではない為3にしました。

リモートワークのマジョリティ度合い

👉「4: 全員が常にリモートワークの可能性がある(出社している可能性もある)」

全員が基本的にリモートワークですが、たまに会社で抽選で配るメロンやチケットなどが当選した場合など、稀に出社することがあります。

申請・許可の必要性

👉「5: 申請や許可は必要ない」

申請は不要です。

リモートワークの適用範囲

👉「5: 業務に関わる全メンバー(正社員以外も含む)がリモートワークを利用できる」

正社員以外も全メンバーリモートワーク利用可能です。

出社義務

👉「4: 年に数回の頻度で出社する必要がある」

入社日はPC等備品受け取りやセットアップの為に出社をお願いしています。

リモートワークで必要なサービス・アプリケーションの取り扱い

👉「4: 業務で利用するサービス・アプリケーションは主にリモートワークを前提としている。一部リモートワークでは利用できないものがあるが、リモートワーク前提のものに移行中・または移行予定がある、あるいは何らかの代替手段によってすべて解決できる。」

基本的にほぼリモートで対応可能ですが、バーコードの精度チェック機など、物理的なデバイスがオフィスにしか無いものも一部あります。

情報のアクセス範囲

👉「5: リモートワーク・非リモートワークでアクセスできる情報に差はない」

差はありません。

その他

✅社内において一定の権限を持つ人物(役員など)がリモートワークを実践している

❎5,000円/月以上のリモートワークに関する手当がある

❎オフィスが存在しない

❎対外的にリモートワークに関する発信・発表を積極的に行なっている

社長も実践しています。またリモートワーク手当は4,000円/月です。

リモートワークの文化

同期・非同期コミュニーションの割合

👉「B: 非同期コミュニケーションが中心だが、一部で同期的なコミュニケーションが必要」 👉「D: 同期的なコミュニケーションが主で、非同期コミュニケーションツールは補助的な利用のみである」 こちらはチームによって状況が違う為、BとDにしました。エンジニアはSlack中心ですが、込み入った話になった場合はMTGも行っています。

テキストコミュニケーションの割合

👉「B: テキストが主で、補助的にビデオ通話・音声通話を用いる」

一つ前の質問と同じですが、Slack中心ですが、込み入った話になった場合はMTGも行っています。

コミュニケーション頻度

👉「B: ミーティングに加え、それ以外でも日々活発にコミュニケーションを取る。雑談もそこそこ。」

毎日朝会を実施しており、それ以外でもSlackでコミュニケーションを取っています。雑談は多くは無いかもしれません。

働く時間

👉「B: 全員働く時間は定まっていないが、コアタイムなどで重なる時間が存在する」

コアタイムはありませんが、チームメンバーで朝会の時間を調整しており、その時間は重なっています。 現在は8:30から9:30の間に業務を開始する人が多いです。

最後に

結構積極的にリモートワークを実施しているのではないかと思います。リモートワークになってから他チームの人たちと雑談する機会がなくなったという声があり、課題になっています。

クオカード デジタルイノベーションラボではソフトウェアエンジニアを募集しています。

OSSへの支援について

クオカードでは様々なOSSを利用していますが、現在は業務として技術的な貢献をする余裕が無い為、寄付という形で支援をすることにしました。

今回は社内の多くのプロジェクトで利用しているJUnit 5に寄付をしました。

https://junit.org/junit5/

今後もJUnit 5に限らず、できるだけ継続的に多くのOSSの支援をしていきたいと考えています。

クオカードではソフトウェアエンジニアを募集しています。

https://quo-digital.jp/

研修体験記:Spring Core(社外)

あけましておめでどうございます、三度のJavaよりメシが好きなデジタルイノベーションラボの山本です。

2022年最初の記事を投稿させていただきます。

年明けにプロダクトグループメンバー数名でSpringFWのハンズオン研修を受講したので今日はそれについて書きたいと思います。

私は、10年以上エンジニア(主にJava)としてシステム開発に携わっており、SpringBootはここ数年よく使うFWとなっております。 基本的なSpringの知識は業務を通じて、中でもわからなかったものに関しては別途本やサイトで調べて補完してきました。 本と言っても、最低限必要そうなところを読むといったスタイルで最初から最後まで通して読んだ本はありませんでした。

弊社でも多くのプロダクトのコア技術としてSpringBootを採用しており、 それぞれバックグラウンドの異なるエンジニアのSpringの知識の平準化を図るべく、社外のハンズオン研修の受講が去年計画されました。 それが実現した、今回受講した研修はこちらとなります。

VMware Tanzu認定 Spring Core: Training https://www.casareal.co.jp/ls/service/openseminar/vmware/v013

研修は、四日間で9:30 - 17:30(昼休憩1時間)で行われました。

1日目:Spring Frameworkの基礎

2日目:アスペクト指向プログラミングに関して

3日目:SpringBoot(MVCトランザクション管理など)

4日目:SpringBoot(REST API作成、Test, SpringSecurityなど)

1〜2日目は、メニュー通りSpringFrameworkやAOPの基本に関して取り扱い、古い記憶をリファインメントしつつ、もちろん中には初めて知ることもある内容でした。 残りの日は、SpringBootを中心に取り扱い、今まさに業務で使用している内容でした。 中でも個人的にはテストケースを書くたためにSpringが提供してくれる機能を一部しか使っていないことを知ることができたのが今回の研修での一番の収穫でした。

私の今までの経験上、とりわけテストケース作成は最初に作成した人のものをベースに右へ倣えで作成していくパターンが多く、 テストケースの書き方を深堀りした記憶も改善しようと考えたこともなく、いかにその状況に「漬かって」いたかを実感しました。

四日間という期間は少し長かったですが、新年のスタートを切るには良い研修経験となりました。 また機会があれば、別の研修にも参加したいと思います。

それでは、メシ行ってきます。

OpenAPI を利用した開発フロー

こんにちは、デジタルイノベーションラボの飯島です。 今回は、OpenAPI を利用した開発とデプロイまでのフローをざっくり紹介します。

アプリケーション構成

バックエンドは Kotlin + SpringBoot, フロントエンドは TypeScript + React になります。 バックエンドが用意した API をフロントエンドが叩く、一般的なアプリケーションです。

フロー

1. OpenAPI 定義出力用の Interface を実装したコントローラーを作成

簡単なサンプルですが、以下のような Interface を作成し、implement してコントローラーを作成します。

@Tag(name = "UserCreate", description = "ユーザーの登録")
interface UserCreateController {

  @Operation(summary = "ユーザー登録")
  @ApiResponses(
      ApiResponse(responseCode = "200", description = "登録成功"),
  )
  fun create(user: User): HttpResponse
}

data class User(val name: String)

実装クラスに直接アノテーションを記載しても良いのですが、API 定義と実装が混在すると可読性が下がるため、Interface を分けています。

アノテーションspringdoc-openapiで提供されているものを使っています。

2. Interface から OpenAPI 定義の yaml ファイルを生成する

openapi-generator gradle plugin を使用し、Interface から OpenAPI 定義の yaml ファイルを生成します。

3. 生成された yaml ファイルから、フロントエンド用のコードを生成する

OpenAPI Generator を利用して、バックエンドの API を呼び出すための TypeScript コードを生成します。 生成されたコードの内部で使用される Http client については、axios や fetch, ajax など複数の中から選択できます。 docker での生成にも対応しているので、バックエンド側で生成した openapi.yml を引数に generator を実行します。

4. 生成された API 呼び出しコードを利用してフロントエンドをコーディングする

React で画面を作り、3 で生成されたコードを使用してバックエンドとやりとりするようにします。 以下のコードでは、UserCreateApi, createConfiguration, ServerConfiguration がそれぞれ自動生成されたコードになります。 先ほどバックエンドの Interface に定義した create メソッドが UserCreateApi に用意されています。

  const api = new UserCreateApi(
    createConfiguration({
      baseServer: new ServerConfiguration(url, {}),
    })
  )

  api.create({
    name: "taro"
  })

生成されたコードも TypeScript なので、型安全に使用することができます。

5. Slack からデプロイする

弊社ではほぼ全てのプロジェクトが Slack からデプロイできるようになっています。 動作確認などで検証環境にデプロイする用にデプロイマン、本番環境にリリースする用にリリースマンという bot を作ってあるので、コマンド一つで GitHub から簡単にデプロイすることができます。

最後に

バックエンドの API 定義箇所とフロントエンドの呼び出し箇所は、受け渡すデータは同じなのに言語が違うことで書き方が変わってくるため、こうして自動化できるとコーディングがかなり楽になります。 open-api generator の具体的な使い方などはまた別の機会に記事にしたいと思います。