RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

コンテキスト共有とモブプログラミング

こんにちは、ラクスル事業本部 SCM(Supply Chain Management)開発チームの藤川です。 RAKSUL Advent Calendar 2021 2日目は私からお届けします!

今日はチームで取り組んだモブプログラミングについてのお話をします。

私事ですが、テックブログ初デビューです。緊張…! 2021年7月入社とチームの中では最も社歴が浅いのですが、チームを代表しての発信の機会をいただきました!

背景

SCM開発チームでは「ラクスルの事業成長を支える発注基盤システムの構築」をミッションとしています。 お客様に高品質・低価格な印刷物をお届けするために複数の印刷委託先と連携してサービス運営をしていく中で、安定稼動を実現しつつも最適な発注によってお客様のより良い購入体験を実現するための仕組みづくりを日々続けています。

さて、そんなSCM開発チームですが現在いくつかの課題を抱えており、そのうち代表的なものは下記です。 どれか一つは「あるある」と思っていただける方も多いのではないでしょうか。

  • システムの歴史が長く続いていく中で正確なコンテキストや仕様を把握しているメンバーが限られており、特定の人にしかレビューできない部分がある
  • ドキュメントが非常に少ない
  • メンバー間でスキル差があり、コードの品質にブレがある
  • 社内の様々なシステムとの連携が必要で、動作検証の実施方法などのノウハウが複雑化している

このように一筋縄ではいかないSCMチームでの開発作業ですが、上記課題の解消を目指して10月の頭ごろから開発体制をモブプログラミング(以下モブプロとします)にシフトしてみました。

その中で得た知見などを、やったこと・よかったこと・気をつけたこと・今後の課題の4本に分けてご紹介いたします。

やったこと

1日の作業をほぼ全てモブ体制で行う

モブ「プロ」と書きましたが、コーディングだけでなくテストやドキュメント作業も常に複数人で行うことにしました。 ちょっとした動作検証のやり方や便利なJenkinsのjobなどの共有も同時に行うことが目的です。

適宜メモを取りながら作業を進める

モブプロの目的の一つをコンテキスト共有としていますが、SCMの開発の歴史は長く、その内容は複雑多岐に渡ります。 ラクスルではNotionを使っているため、共同編集機能をうまく使いながらみんなでメモを取ることにしました。

先述した「ちょっとした動作検証のやり方」なども積極的にメモを取ることにしています。

ファシリテーターを置く

モブプロ中は全員で議論をしているので、つい時間を忘れて盛り上がってしまうことも少なくありません。 そして時には、その話題は全体の優先度から考えてあまりこだわるべきでないはずなのに、つい盛り上がってしまって想定以上に時間を使ってしまう…という事態が起きることもありました。

そこでモブプロの「場」を俯瞰する立場としてファシリテーターのポジションを設け、ちょっと議論が込み入ってきそうな時に 「ここって今この場で解決しきってしまいたい話題でしたっけ?」などの言葉でみんなの意識を引き戻す。というようなことをしています。

その他にも休憩時間を管理したりその日の作業内容を認識合わせしたり、モブプロのために設けた時間中に各メンバーにミーティングがかぶったりしていないかの確認とリマインドなど 開発作業に集中しているとつい疎かにしてしまいがちな部分はファシリテーターがある程度拾うようにしました。

よかったこと

みんなが同じ目線を持って開発できるようになってきた

長く開発している案件がある中で新規メンバーがjoinした場合「いきなり全部説明して理解してもらうのも大変だし、まずは簡単で分かりやすいタスクを…」と 軽微な改修などから少しづつキャッチアップしてもらう形式を取ることが多いと思いますが その間新規メンバーからすれば他のメンバーが何をやっているか、またその目的は何かなどがよくわからないままだったりします。

しかしプロダクト開発においてはその長く開発している案件こそがそのチームにとっての最大の関心事であり、かつ中長期的な価値を生み出すものであることも少なくありません。

今回モブプロをすることによってその目的や背景を知ることができたため、担当プロダクトが持つ本当の価値について同じ目線を持つことができるようになり、チームとして一体感が増したように思います。

私見ですが、モブプロで得たものの中ではこれが一番大きいと感じました。

リソース効率の面で考えると簡単なタスクを渡すほうが効率はよいですが、早期のキャッチアップを目指すのであれば多少リソース効率を落としてでもモブプロで実開発をしながら説明を行うほうがよいと思います。

レビューにかかる時間がほぼゼロになった

全員で一つの開発作業に取り組んでいるため、その成果物には全員で議論した内容が既に盛り込まれています。

そのためレビュー時に上がる新たな指摘はほぼゼロで、あっても細かい修正(ユニットテストのケース名など)のレベルにまで減らすことができました。

お互いのサービス・技術への理解度を知ることができた

日々の業務をリモートワーク体制で行う中、SlackでのやりとりやGitHubのPull Request上での会話だけではやりとりの相手がプロダクトのコンテキストや技術への理解度をどれくらい持っているのか不明瞭なことが多いです。 特に私などはコロナ禍中での中途入社、他のメンバーがどの領域にどれくらい詳しいかを推測しながら日々の業務を行うのはとても困難でした。おそらくみんなも私に対して同じ意識を持っていたのではと思います。

ですがモブプロで日々会話を重ねることでそれらをお互いに確認することができ、以後は相手の理解度に合わせたやりとりをスムーズに行うことができるようになりました。

メモの内容をドキュメントに繋げることができた

SCM開発チームは歴史が長いものの、ドキュメントはまだまだ整っていないところが多くあります。

今回のモブ体制はドキュメント充実が目的ではないものの、モブプロ中に取ったメモを空き時間で簡単なドキュメントとして書き直すことでナレッジを明文化することができました。

集中した状態を長く続けることができる

モブプロの場では常に議論や実装が進んでおり、普段の業務なら立ち止まってしまうところでもスムーズに進むことが多いです。

結果、全員がほぼ常に集中している状態で作業を進めることになり、脳のリソース効率が非常に良いと感じました。

気をつけたこと

意識的に休憩を挟む

先述の通りですが、モブプロの場では集中した状態を長く続けることができます。

反面、集中した状態で作業をしているとつい休憩することを忘れて作業を続けてしまうことが多くなりがちですし、集中した状態を長く続けること自体とても疲れてしまいます…

結果、適度に休憩を挟まないと業務終了後はグッタリしてしまうことも多く… 以後は作業開始時にアラームを設定してから開発作業に臨むようにしました。

行き詰まったらそのタスクは後回しにできないか検討する

作業中に困難に当たった結果行き詰まってしまい、作業が進まなくなった状態のまま時間が経過してしまうことを「ハマる」と呼ぶことがあると思います。

モブプロの場で全員でハマってしまうと、ハマった時間 × 人数ぶんの時間が飛んでしまいます。 タスクの内容やタイミングにもよりますが、ハマってしまった場合はタスクを後回しにしたうえで別タスクとして解消や調査のための時間を取れないか検討することにしました。

ドライバーが率先して進めすぎないようにする

最初に書いた通りですが、現在SCM開発チームではメンバー間でスキルや担当プロダクトについての理解度に差がある状態です。

ですので理解度や技術力の高いメンバーがドライバーになってしまうと、ドライバーは最初からどう実装すればよいか分かっている状態なのにナビゲーターは調査してみないと正しくナビゲートできない…という状態になることも少なくありません。

ドライバーは作業をスムーズに進められる状態にあるため実際にコーディングを進めてしまいますが、状況理解が追いついていないナビゲーターが置いてけぼりに… というようなことがあり、掲題の通り「ドライバーが率先して作業を進めすぎないようにしましょう」と意識的に決めました。

具体的には2つのことを実施しています。

  1. テックリードはドライバーにせず、ナビゲーター限定での参加とする
  2. 実装方法などについて議論する際は、必ず全メンバーの理解度を確認する

今後の課題

「自分の力でやりきったぞ!」という達成感が得づらい

モブプロでは全員で思考し、全員で議論し、全員で開発します。ですのでその場で出たアイデアは「全員で出したアイデア」という認識を自然と持つことになりやすいです。

ですので、個人にタスクを割り当てて開発をしている状態(モブプロでないとき)では難しい実装をやりきったり 自分で考えたアイデアをPull Request上で他の人から「いいですね!」などと言われたりすると達成感があり嬉しい…!みたいな気持ちがあると思うのですが、そういった感覚を得づらいことがあります。

モブプロ期間がある程度続くとチーム内から「もっと自分の力でコードを書きたい」などの声を聞くことがあり、この辺りはタスクを調整したうえでモブプロする日・しない日を定めてみてもいいかも?と思いました。

簡単なタスクでも時間を使うため、チーム全体としての進捗が気になる

これは我々がモブプロをする目的の一つに「コンテキストや仕様の共有」を置いている以上、必要なコストとはしているのですが ある人には背景や修正箇所がわかりきっているタスクでも、全員の理解を促すために解説をしたり足並みを揃える時間を取る必要があります。

結果的に1週間を通してチーム全体でアウトプットできる分量が少なくなり、「当然とは分かっていてもアウトプットの量が少ないと不安」という感情が湧いてくることがありました。

じっくり考える時間を取りづらい

皆さんは普段、設計やコーディング段階でふと違和感を覚え「何か忘れている気がする…」などと考えこむ時はありませんか?(私はあります)

じっくり考えることで新しいアイデアが思いついたり忘れていたものを思い出せたりすることもよくあると思うのですが、モブプロでは常に皆で議論しながら作業が進む状態であるため、この「ひとりで考えこむ時間」が実質的に存在しません。

そのため、いつもなら時間をかけて考えれば気付けたはずの考慮漏れが起きたり、後になって「そういえばこんな実装方法もあったな」と思いついたりと、普段なら作業中に気付けたはずのことを後になってから気がつくというようなことが増えました。

これについてはまだ明確な対策を打つことはできていないのですが、ひとまず必要コストとして割り切ってしまい、気がついたタイミングで別途チケット化などを行うようにだけしています。

ファシリテーターが大変

先述したファシリテーターは、他のメンバーと同様にドライバーやナビゲーターとしてモブプロに参加している状態です。

ですので、時には議論に積極的に参加したり、時には場のことを考えて議論をストップさせたりなどの判断をする必要があり、そのため開発や議論に集中しきれないこともしばしば…

ファシリテーターは一貫して私が務めているのですが、気を多く遣って非常に疲れるので、ある程度ノウハウが溜まったら明文化して他の人でもできるようなると嬉しいなーと思いました。

最後に

以上、約2ヶ月ほどモブプロをやってみた中での感想やノウハウでした!

最後に個人的な感想としましては、モブプロは働き方をある程度変えて行う取り組みなので、もし試験的に導入する場合でもある程度慣れるまで続けてみるとよいのかなと思います。

今回はチーム全体としてのアウトプット量などある程度トレードオフにしたものもありますが、チームビルディングやキャッチアップなどの観点からリターンの大きい取り組みだと思います。もし今後「モブプロってどう?」などと知人から聞かれたらオススメしたいなと思いました!

今回は長くなりすぎるため書けませんでしたがモブプロの場は技術継承の場としても非常によく、リモート環境下でのティーチングに悩んでいる方は是非試してみてはいかがでしょうか?

ラクスルではエンジニアを募集中です!

マイクロサービスドキュメントガイドラインを策定した話

RAKSUL Advent Calendar 2021 1日目です!なんとトップバッターです!

こんにちは!今年8月に発足したラクスル事業本部 HoE(※)室 の市島です!

※ HoE:Head of Engineering

記念すべき RAKSUL初のAdvent Calendar 1日目、今回はラクスル事業部にてマイクロサービスを開発する際、そのサービスを組み込む(利用する)開発者に向けて書くべきドキュメントのガイドラインを策定した話について述べます。

はじめに

ラクスルでは日本国内だけでなく、インド・ベトナムでのグローバル採用も行なっており、ラクスル事業部ではエンジニアだけであれば、およそ40%の人が日本以外の国籍です。(2021/12/1時点)

今後も積極的に採用していく予定であり、このペースであれば2年後には50%に届く勢いです。

ラクスルにはチラシやポスターなどの印刷商品を扱うraksul.comだけでなく、マスクやお菓子といったノベルティを扱うnovelty.raksul.com、ダイレクトメールを扱うdm.raksul.comといったサブドメインを持つECサイトがあります。

各ECサイトは独立して開発をしていますが、内部にはこれらの複数サービスを横断した決済基盤システムや入稿されたデータのチェックを行うデータチェック基盤システムといった基盤系システムが存在します。

ここでは一旦上記のような基盤系システムをマイクロサービスと呼称します。

やったこと

しかしながら、こういった基盤系システムを組み込むにあたって必要なドキュメントが散らばりがち、かつ日本語であるため、日本語ネイティブではないメンバーとしては組み込みがしにくく、基盤系システムの開発をするメンバーはその問い合わせへの対応工数が増加しているという問題がありました。

そこでHoE室では、マイクロサービスドキュメンテーションガイドラインを策定し、基盤系システムのユーザに向けたドキュメントの作成指針を設けることで、この問題を解決しようと試みました。

Principle

今回策定したガイドラインには以下のPrincipleを定めました。

  • EASY INTEGRATION
    • 組み込みたいエンジニアがドキュメントを読めば組み込める状態であるべき
  • REACHABLE
    • repositoryのREADMEがドキュメントルートであり、そこから開発に必要なドキュメント全てにアクセスすることが可能であるべき
  • OWNERSHIP
    • 良いドキュメントを書くことまでがマイクロサービス運営者の責務である

具体的な内容

上記のPrincipleを具体に落とし込んだ内容が以下になります。

ユーザファーストであること

READMEの構成はユーザガイドが先頭にあるべきだと規定しています。その理由としては基盤系システムの開発者より基盤を利用する開発者の方が多いこと、また基盤系システムから見て、その基盤系システムを組み込む側の開発者はユーザであるという視点を持ってほしいという意図があります。

開発に必要なドキュメントはGitHubのrepositoryのREADMEから辿れるようになっていること

READMEさえ見れば、組み込みに必要な情報は全て揃うようになっているべきと規定しています。

ラクスル事業部ではREADMEと定めていますが、ここは決めの問題で、定めた場所に必要な情報がしっかりと集約されている状態になっていることが重要だと考えています。

コンテンツについて

ユーザガイドには以下のコンテンツを書くべきと定めています。

  • TOC(Table of contents)
  • What is this?
  • Getting started
    • アクセストークンの生成方法やクライアントの利用方法といった組み込みに必要なプロセスを書く
  • Concepts(optional)
    • ハイコンテクストなドキュメントを避け、エンジニアがサービスを理解するためにそのサービス内の重要なコンセプトを説明する
    • 例えばデータチェック基盤では「Operator Commission」という概念が出てくるのですが、これはオペレーターの目でデータをチェックするというデータチェック方法の1つである、といった旨の説明がされています
  • API reference
  • Example (optional)
  • Owner
    • オーナーが誰かを連絡先(slack channelやgroup mention)と共に書く
    • 誰がこのドキュメントを管理しているかを明確にし、何を書くべきかを把握してもらうことで、各マイクロサービス運営者にOWNERSHIPを意識してもらおうという意図があります

翻訳ポリシー

少し毛色が違うのですが、日本語と英語を併記する場合の翻訳ポリシーについても記載しています。基本的には英語のみで書きましょう、というのと「日本語も併記する場合はこうしてね」といった書き方を定めています。

おわりに

HoE室では前述の原則を定め、これが絵に描いた餅にならないようにするべく、重要なドキュメントを英訳し、また社内での具体的なお手本とするためにいくつかのrepositoryのREADMEをガイドラインに沿ってUpdateしました。

ラクスル事業部では、まずマイクロサービスのドキュメントというスコープに限定してガイドラインを策定することで小さく始めています。今後はこのスコープを広げていき、最終的にはマイクロサービスに限らない「ドキュメントガイドライン」を定めて、しっかりと運用させ続けることができればゴールなのではないかと考えています。

ラクスルではエンジニアを募集中しています! https://recruit.raksul.com/career/engineer/

ラクスルのアドベントカレンダー全編はこちらから

AWS CDK利用時にハマった点 3選

こんにちは。今年8月に発足したラクスル事業本部 HoE(※)室 の市島です。

※ HoE:Head of Engineering

はじめに

以前公開した「Permissions Boundaryでガードレールを設けてAWS CDKを安全に使う」という記事の中でも紹介していますが、HoE室ではAWS CDKとPermissions Boundaryの組み合わせで、高速かつ安全にサーバーレスアプリを開発しています。

ラクスルではSecrets Managerに登録する秘匿情報やKMS、S3のバケットはインフラチームによって別管理されています。また、CDKはTypeScriptで書いています。

上記の前提で、開発中にハマってしまった点を3つほど紹介できればと思います。

権限の付与忘れがち

CDKでは利用するAWSのサービスに対してよしなに権限を与えてくれるので非常に便利なのですが、こちらから明示的に権限を与えてやらないと動かない場面があったりします。

例えばLambda内でSecrets ManagerからAPI Tokenなどの秘匿情報を取得するとなった場合、以下のようにSecrets ManagerへのRead権限を与えることが必要になります。

const secret = secretsmanager.Secret.fromSecretNameV2(this, 'Secret', 'secret')
secret.grantRead(lambdaFn)

secretsのdecodeにはKMSへのアクセス権限も必要になるため実際これだけでは動かず、以下のようにKMSへの権限も別途付与する必要があります。

const kmsPolicy = new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ["kms:Decrypt"],
      resources: ["*"],
    })
    
lambdaFn.addToRolePolicy(kmsPolicy)
const secret = secretsmanager.Secret.fromSecretNameV2(this, 'Secret', 'secret')
secret.grantRead(lambdaFn)

またLambda内で既存のS3のバケットにアクセスするには、バケットに対してLambdaが読み書きできる権限が必要でした。

const bucket = s3.Bucket.fromBucketName(
  this,
  'bucketName',
  'bucketName'
)
bucket.grantReadWrite(lambdaFn)

Docker Hubのrate limit引っかかりがち

CD(Continuous Delivery)にはCodePipelineを使っており、CodeBuildにてgolangで書かれたLambdaのdocker imageをbuildするプロセスがあります。

このプロセスでDocker Hubからimageをpullしてくる際にrate limitに引っかかることがありました。

対策としてはdocker loginするのが手っ取り早いです。既に社内のdockerアカウントは存在していたので、そのアカウントでのdocker loginの処理を追加しました。

const dockerHubSecret = secretsmanager.Secret.fromSecretNameV2(this, 'dockerHubSecret', 'dockerhub');
const kmsPolicy = new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: ["kms:Decrypt"],
  resources: ["*"],
})
const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
  dockerCredentials: [
      pipelines.DockerCredential.dockerHub(dockerHubSecret)
  ],
    codeBuildDefaults: {
    rolePolicy: [kmsPolicy]
  },
...

しかしこれでもrate limitにひっかかることがありました。

調べてみると、記事執筆時点ではワークアラウンドな対策しかありませんでした。(issue #15737)

そのため、今はdockerCredentialsを以下のように記述することでrate limitに引っかからないようにしています。

dockerCredentials: [
  pipelines.DockerCredential.dockerHub(dockerHubSecret),
  pipelines.DockerCredential.customRegistry("<https://index.docker.io/v1/>", dockerHubSecret)
],

マルチアカウントでの運用方法を迷いがち

CDKを使ってアプリケーションを構築する際、本番環境・開発環境など複数のAWSアカウントに対してデプロイをすることが多いでしょう。このとき、アカウント毎にリソースの定義や振る舞いを変えたい場合があります。私たちのアプリケーションでは、参照するAWSリソースやLambdaの振る舞いをアカウント毎に変える必要がありました。

これを実現する方法は、以下の2つが考えられます。

  • アカウント毎に別々のStackを作る
  • Contextを使って依存性を注入する

「アカウント毎に別々のStackを作る」場合には、それぞれのStackにアカウント固有の情報をハードコードすることで、アカウント毎にリソース定義を変えられます。

「Contextを使って依存性を注入する」場合には、CDKのContextを使います。Contextは、StackやConstructに渡すことができるkey-valueペアで、cdk.jsonのような設定ファイルやcdk deploycdk synthのオプションから与えることができます。

今回は「Contextを使って依存性を注入する」方法を採用しました。まずcdk.jsonに以下のような設定を追加します。

"context": {
    "accounts": {
      "dev": {
        "arn": "xxxxxx"
      },
      "prod": {
        "arn": "yyyyyy"
      }
    },

さらにcdk deploycdk synthの際に、envというcontextを設定するようにします。

$ cdk deploy -c env=dev # 開発環境にデプロイ
$ cdk deploy -c env=prod # 本番環境にデプロイ

これらのContextを読み込む処理をStackに追加します。まず、envの値を読み込みます。この時、値が設定されていない場合には終了するようにしています。

const env = scope.node.tryGetContext('env')
if (env == undefined) {
  console.log('"env" must be set to context.')
  process.exit(1)
}

次に、cdk.jsonに定義した値を読み込みます。まずaccountsを読み込み、そこからenvに対応する値を取り出します。

const accounts = scope.node.tryGetContext('accounts');
const accountConfig = accounts[env]

例えばenv=devとした場合には、accountConfigに入る値は以下のようになります。

{
  "arn": "xxxxxx"
}

ここから各種設定値を取り出します (実際には複数の設定値を取り出しています)。

const arn = accountConfig['arn'];

あとはCDKの定義にこの定数を使えば、アカウント毎にカスタマイズしたリソースを定義することができます。

また以下のようにLambdaの環境変数にcontextから読んだ値を渡すことで、依存性注入が可能です。

const sampleFn = new lambda.DockerImageFunction(
      this,
      'sample',
      {
        functionName: 'sample',
        code: lambda.DockerImageCode.fromImageAsset(
          path.join(__dirname, '../../lambda/sample'),
          {}
        ),
        environment: {
          APP_ENV: env,
        },
      }
    )

Lambdaのアプリケーションコードにて、環境変数APP_ENVによって処理を書き分けることで、アカウント毎にLambdaの振る舞いを変えることができます。

おわりに

AWS CDKを用いると、Cloudformationのテンプレートを長々書かなくてもよくなり、普段慣れ親しんだプログラミング言語で型補完を効かせながらスイスイ書くことができます。

CDKはよしなにやってくれるので非常に助かる反面、意識していないとハマるポイントもあります。サービス自体が比較的新しく現時点ではそこまで情報が多いわけではないので、この記事が何かのお役に立てば幸いです。

ラクスルではエンジニアを募集中です!

Permissions Boundaryでガードレールを設けてAWS CDKを安全に使う

こんにちは。今年8月に発足したラクスル事業本部 HoE(※)室 でインターンをしています、灰原です。

HoE室では、プロダクト開発チームの生産性を可視化するのための社内システムを開発しています。このシステムはAWS上にサーバーレスアプリケーションとして構築しました。構築の際に問題となったのが、新たにAWSリソースを追加する際に発生する、インフラチームと開発者側とのコミュニケーションコストです。この記事では、迅速な開発と堅牢な統制を両立させるために、AWS CDKとPermissions Boundaryを組み合わせて利用する方法をご紹介します。 ※ HoE:Head of Engineering

AWS CDKの導入

前述の社内システムは、大まかに以下のようなアーキテクチャになっています。Lambda関数でGitHubやClickUpなどのAPIを叩いてその結果をS3に保存し、Glueを通してS3内のデータをAthenaでクエリするというものです。実際にはLambda関数やGlueテーブルは複数あり、今後も増えていく予定です。 弊社ではAWSのリソースをTerraformで構築しており、このTerraformをインフラチームが管理しています。そのためAWSのリソースを変更する場合には、TerraformのレポジトリにPRを送るか、インフラチームに作業を依頼する必要があります。

例えばLambda関数に渡す環境変数を追加したり、Glueテーブルのフィールドを1つ修正したりするような軽微な変更であっても、インフラチームには工数が、開発側には待ち時間が発生します。これではサーバーレスであることの恩恵が小さく、インフラ・開発双方の負担が大きくなってしまっていました。

この問題を解決するため、AWS CDKを導入することにしました。AWS CDKは、TypeScriptやPythonなどのプログラミング言語でAWSのリソースを定義してデプロイできるフレームワークです。上図のLambda関数やGlueテーブルなどをCDKで定義し、これを開発側で管理できれば、インフラチームとの調整なしにリソースを変更できます。

ここで問題になるのが権限の管理です。例えばAthenaのクエリを実行するLambda関数を追加したい場合、新たにIAMロールを作成する必要があります。しかし、IAMロールを自由に作成できる権限を開発側に与えてしまうのは、統制の観点で避けるべきです。このようなジレンマを解消してくれるのがPermissions Boundaryという仕組みです。

Permissions BoundaryでIAMロールの発行を制限する

Permissions BoundaryはIAMの発行に対して制限をかける機能です。Permissions Boundaryを使えば、IAM管理者が設けた制限の範囲内であれば自由にIAMを作成できるようになります。このPermissions BoundaryとCDKを組み合わせることで、開発者がCDKで定義するリソースに対してインフラチームが制限をかけることができます (下図)。こうすることでインフラチームが設けた制限の中で、開発者が自由にリソースを定義できるようになります。 CDKでPermissions Boundaryを設定するコードは以下のようになります。

const app = new cdk.App(); 
const stack = new CodePipelineStack(app, 'PipelineStack'); 
const policy = iam.ManagedPolicy.fromManagedPolicyName(stack, 'PermissionsBoundary', 'RestrictedAccessBoundaryPolicy'); 
iam.PermissionsBoundary.of(stack).apply(policy);

PermissionsBoundary Class を使って、stackで使われる全てのIAMロール・IAMユーザーに対して、policyをPermissions Boundaryとして適用しています。ここでstackはリソースを定義したクラスのインスタンスです。またpolicyはインフラチームがTerraformで定義したIAMポリシーです。これでPermissions Boundaryの制限についてはインフラチームが、CDKで定義する内容については開発者側がそれぞれ管理できます。

おわりに

AWS CDKとPermissions Boundaryの組み合わせで、高速かつ安全にサーバーレスアプリを開発できるようになりました!

今回のAWS CDK導入に関しましては、インフラチームのKobayashiさんに多大なるご協力をいただきました。ありがとうございます。

ラクスルではエンジニアを募集中です!

Hack Week/ID基盤開発インターンチームレポート

こんにちは、エンジニアの泉田です。ラクスルでは先日8/30から9/3にかけてHack Weekを実施しました。Hack Weekはラクスルで開催している年1回、約1週間のハッカソンです。今年は4回目となり、日本、ベトナム、インドのオフィスのエンジニアから、サマーインターンの学生まで含めて、総勢約120名での過去最大人数での開催となりました。詳しくはこちらの記事 もご覧ください。

今回はインターン生中心のチームにレポートをまとめていただきましたので、そちらをシェアさせていただきます。Hack Week 1週間では、プロジェクト全体の一部のみでしたが、是非今後とも追加開発を進めていきたいと思っています!!

Hack Week レポート(ID基盤開発チーム)

全体の特徴

私たちのインターンチームではインターン生4人に対してメンターが2人つく、とても豪勢な布陣でした。他のチームも3~4人のインターン生のグループに対してメンターがついていました。

また、社内ハッカソンの形式なので、最終日の発表会で他のチームの発表(これも業務改善やDX改善, ビジネス案など)が見られて、社内の雰囲気も感じることができました。

オンラインインターン

今回のインターンはすべてオンラインで実施されました。 Slack、Google Meet、VS Code Live Share等のオンラインツールを活用し、オフライン開催と遜色ないインターンになったと思います。

開発の特徴

チームごとに開発の特徴は異なりますが、私たちのチームでは、6人(インターン4+メンター2)のチームが開発領域ごとに3人ずつのグループに分かれ、モブプロ・ペアプロでスピーディに開発を進めました。インターン生2人のペアプロにメンターが6時間近く密着して指導していただけたので、とても密度の高い1週間でした。

ハッカソンという形式ですが、実運用されているリポジトリに触れられて、既存のアプリケーションとの結合が経験できる点はとても貴重でした。そして、開発したアプリケーションもこの場限りのアプリケーションではなく、今後も使われるのが期待できるのが刺激的でした。

社員さんとの関わり

ハッカソンといえどインターンなので、会社の雰囲気やラクスルで実際に働いている社員さんのお話を聞く機会はインターン生としてもぜひ欲しいところです。しかし、今回はオンラインでの開催なので会社で直接お話を聞くことはできません。インターンの中盤に新卒の方とランチする時間(任意参加)を用意していただき、貴重なお話ができました。インターン生からのかなり直球な質問に対して、しっかりと回答いただけて会社についての解像度が上がりました。

今回実装したアプリケーションについて

背景

現在ラクスルは、最も長く運用しているメインの印刷ECサービスであるraksul.comの他、ノベルティ、ダイレクトメール、見積もりサービスなど毎年新しいサービスをリリースしながら、複数のECサイトを運用しています。raksul.comはECとしての機能開発を頻繁に行っている他、複数サービスを横断したラクスルユーザーとしての認証まわりも扱っています。

この一つ目の課題として、raksul.comでのEC機能のリリース等で何か障害がありサービスがダウンした時に、他のnovelty.raksul.comやestimate.raksul.comなどのユーザー認証もエラーとなり、使えなくなるリスクがあります。

また二つ目に、それぞれのECサイトの注文は各サイトのフォームにて管理をしているのですが、複数サイトを横断した同じラクスルアカウントの注文管理画面がないため、社内オペレータが、あるユーザーの注文情報を横断で調べる時に、手間がかかるという課題があります。

アプローチ

上記の課題を解決するため、アカウント情報(ユーザー情報とその注文情報)を管理できる、アカウント基盤を構築することにしました。そのまず第一歩として、このHack Weekの一週間では、ユーザー情報を Raksul のDBからAccount DBへ移行のための同期処理と、アカウント管理画面の実装を行いました。Accountのアプリケーション作成にはRuby on Rails、スキーマ定義には Protocol Buffers、同期にはApach Kafkaを使いました。移行期間中はRaksul DBからAccount DBへと、それぞれが並行で更新される状態になりますが、最終的にはAccount DBのみを直接更新することを想定しています。

アカウント管理画面は以下のようなイメージです。まだ未完成ですが同期したデータを確認できるところまで開発が終わりました。

開発を通しての学び

開発を通して知ったこと

  • 開発は終始ペアプロで行いました。ペアプロはナビゲーターがドライバーのコーディング画面を見ながら指示する方式で、1人で手を止める時間が減る分、速度・密度が高くなります。ペアプロをやる前はn人分の1のスピードになるかと思っていましたが、予想以上に開発がスムーズに進み、追いつくので必死なくらい高速でした。また、一見ナビゲーターが手持ち無沙汰になりそうですが、実際にはドライバーより考えることが多く、ナビゲーターも多くの経験値を得られる内容でした。モブプロ・ペアプロの面白い点として、自分以外の人のコードの書き方を注意深く見るため、新しい気づきが多いところがとても新鮮でした。ただ、何よりペアプロは集中力を使うので、気づくと数時間熱中し続けてヘトヘトになっているということが初日はありました。そのため、ポモドーロテクニックを入れるなど、生産性を高める方法を工夫しながらやっていきました。
  • メンバーによってgitの使い方が異なることが分かりました。一人はターミナルでgit、また一人はVS CodeのGUIでgit、VS Code内のターミナルでgit、tig ...と様々で、gitの活用方法を色々見ることができて楽しく、学びにもなりました。

技術的なこと

  • メインの技術
    • Ruby on Rails
      • 現在Raksulのバックエンド開発メインのフレームワークです。
    • Protocol Buffers
      • schema定義用の記述形式。Raksulではよく複数アプリケーションのRPC型定義に利用しています。
    • Kafka
      • システム間のデータの受け渡し時に、データを一時的に保存する働きをする、メッセージキュー。

  • スキーマ設計時の工夫
    • DBのカラム名:既存のRaksul DBのユーザーテーブルは10年近くも前に定義されたものであり、意味を読み解くことが難しいカラム名もありました。今回のAccount DBは可能な限り理解しやすいカラム名にするなど工夫をしました。例: c_name を company_name, rtime を registered_at など
    • 型の再定義:カラム名と同様、新Account DBではより管理しやすいようにテーブルやprotocol bufffersの型を定義しなおしたものも多々あります。Protoの定義は、Raksul DB から Account DBへこれらを受け取り側にとって扱いやすく、変更に強いデータの形式になるよう工夫しました。結果的に、string にすることが多かったです。
  • TriggerとStored Procedureのmigrationファイルでの設定
    • Raksul DB は二つのアプリケーション(PHPからRailsへとリビルド途中)から更新されているため、新Account DBへのユーザー情報の同期を漏れなく行えるようテーブルへの更新をトリガーに行えるように設計しました。
    • Stored Procedureにより、Queueテーブルに更新対象のuser id を保存し、後続のデーモン Task で Kafka へとproduce します。既存データベースの制約により、Railsのmigrationでは素直に記載できない箇所はSQLでmigrationを書く必要がありました。また、これらの反映とロールバックを繰り返し行えるような記載など、考えることは多かったです。
  • Kafka へのProduce のためのTaskの作成
    • KafkaへのProduce には、ユーザーテーブルの更新に伴いトリガー経由で作成したデータ(Queueテーブル)を Rails のTaskから参照して行うように実装しました。
    • 元のDBから、カラムの選定やデータの整形をする必要があり、自動でRailsのModelからProtoでの形式に変換するようにしました。
  •  テスト
    • RSpec
      • テストを書いた経験があるインターンメンバーは少なく、テスト項目の切り出しから苦労しました。
      • テストコードが、テスト内容を説明する文章になるところは、理にかなっていて面白かったです。
    • FactoryBot
      • テスト用にあらかじめテスト用データを設定できるGem。複数ユーザーのテストデータをFakerと合わせて作成しました。
    • Faker
      • いい感じのテストデータの値をRandomに生成してくれるGem。

まとめ

メンターの方々がずっとmeetで見ていてくださったので、技術的にわからないところをすぐに聞ける雰囲気が形成されていたところがとても良かっです。感想として、最初の3日間でメンバーがそれぞれ蓄えた知識を4日目で爆発させて、5人全員でLiveShareでフォームやシードデータ作成など、爆速で同時に開発が進むところは壮観でした。また、最終日には全チームの様々な成果発表を見られたのも面白く、最後のオンライン懇親会含めてとても楽しむことができました。