RAKSUL TechBlog

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

テレワーク 相手を知らず 照れわーく

はじめに

はじめまして。サーバーサイドエンジニアの藤本です。

ネット印刷サービスであるラクスルを開発・運用しているPBU(Printing Business Unit)チームに所属しています。

本日はRAKSUL Advent Calendar 2021 4日目です。

ラクスルにjoinして、早いもので3ヶ月が経過しました。ラクスルは2013年より開発、保守されているシステムで非常に巨大なシステムになっています。キャッチアップが大変だったのですが、チームメンバーの手厚い協力もあり、ようやく機能追加を行える程度には理解が進みました。

そこで、先日リリースした折りパンフレット・ポスターのお届け予定日指定機能の開発リードをしました。

その中での学びや気づきを記事にしたいと思います。

お届け予定日指定機能とは?

ラクスルではチラシやポスターなど、様々な商品を扱っています。その中でチラシの注文時にお届け予定日を指定出来る機能を約1年前にリリースしました。

チラシのお届け予定日リリースでの反響を受け、今回はポスターと折りパンフレットでもお届け予定日を指定出来るように開発しました。

各商品で指定可能なお届け予定日のリストは私たちが開発・運用しているECシステム側では管理しておらず、別チームが開発している委託先管理・発注システムにAPI経由で問い合わせています。

ラクスルはユーザーが注文しようとしている商品カテゴリ(チラシ、ポスターなど)や商品仕様(用紙サイズや紙の種類など)をリクエストパラメータに含め、委託先管理・発注システムにお届け予定日の問い合わせをしています。

開発をしていく中での気づき

フルリモート下での他チームとのコミュニケーションの難しさ

私は2021年9月にラクスルにjoinしましたが、ラクスルでは当時フルリモート勤務になっていました(チームビルディングの観点より11月より週1出社を開始しています)。

開発を進めていく上で見えてきた課題感

印刷ECのシステムと委託先管理・発注システムが別れている

ラクスルでは開発手法にスクラムを用いており、スクラムチーム単位での開発を行っています。各スクラムの活動内容は共有されるものの、システムの詳細な仕様は把握できていません

お届け予定日のリストは委託先管理・発注システムから取得しますので、他チームとコミュニケーションをとって開発を進めていく必要がありました。

他チームとのやり取り

入社して日が浅く、リモートでは自チームメンバーとのコミュニケーションが中心になることもあり、他チームのメンバーの人となりをよく知らない中で、コミュニケーションをとるのに心理的な障壁がありました。

そのような状況の中、認識があっているか何度もヒアリングをする必要がありました。

ドメイン知識の不足

ラクスルでは多くの商品を販売しており、それらの属性がソースコード上に定義(ex. 仕上がりサイズのA4の1/3仕上がりは "A4_ONE_THIRD")されています。サイズや色、パンフレットのおり方などなど。ソースコードに書かれているものがどの商品定義にあたるのかをパッと頭の中で紐づけるのが難しいです。

ex.size=A4_ONE_THIRD&color=BOTH_SIDE_COLOR&paper=WOODFREE&weight=135&amount=100&business_day=2&folding=HALF&crack_prevention=CRACK_PREVENTION_OFF

また、ECサイトと発注システムは異なるシステムですので、ソースコード上での定義が異なるケースがあります。ECサイト側では、A41/3仕上がりは "A4_ONE_THIRD"ですが、発注システムでは、 "ONE_THIRD_OF_A4" と定義されています。このあたりのパラメータの定義の変換を行う必要がありました。

課題解決のためのアプローチ

上記の課題感への対応として、下記を意識して行いました。

他チームを含めたオンラインMTGを設定し、パラメータの認識合わせを実施する

現状を整理し、自チームの認識している内容をドキュメント化することで、他チームとの認識内容に齟齬がないかを確認しました。

また、他チームのメンバーにコードレビューをしてもらうことで、認識にズレがないことを確認しました。

ぐいぐい聞く 🍶

上述したように人柄を把握していない人とコミュニケーションをとっていくのは大変ですが、他チームのメンバーもそれは同じだと思いますので、まず自分からここがわからない、こう考えていますが合っていますか、とコミュニケーションをとるようにしました。

とにかく自分の考えや意思を表に出すことを意識していました。

ラクスルにはCo-Operationの文化があり、チーム外からの質問や相談にも積極的に対応してくれます。

コミュニケーションを取る際には、Slackでのコミュニケーションが活発なので、さらっと聞いてみたり、最近ではhuddle(Slack上の音声会議)も利用してサクッと相談することにしています。がっつり仕様を確認したい際にはGoogle Meetで顔を合わせながらやるようにしていました。

ローカル開発の複雑さ

前述の通り、お届け予定日のリストを取得するには委託先管理・発注システムとの連携が不可欠なのですが、そこでも課題が見えてきました。

開発を進めていく上で見えてきた課題感

APIのリクエストに成功すると、APIのレスポンスを正しく処理できているかの動作確認が必要となります。APIのリクエストに成功しているかどうかの確認が簡単に行えない状況でした。

課題解決のためのアプローチ

ここまで記載した通り、他チームの開発しているアプリケーションに依存する機能となっていますので、動作確認をするためには、下記2点のどちらかの方法をとる必要がありました。

  1. ローカルに他チームアプリケーションの開発環境を整備する
  2. 他チームのアプリケーションがデプロイされているテスト環境が存在するので、そこに自チームのシステムもデプロイする

1. の方法は、ラクスルは商品ごとのマスターデータが非常に多く、他チームのアプリケーションを動作させるのにどのデータを投入するかを判断することが難しかったです。Docker環境が現在整備中(詳細後述)なこともあり、環境構築にかかるコストが高くなりそうでした。

2. の方法は、テスト環境では本番に近いデータが用意されており、またラクスルはデプロイが高速で、早ければ5分もかからない環境になっています。認識合わせを事前に行った上でコードを作成すれば、それほど多くのデプロイをする必要もないと想定しました。

そのため、今回は2の手法を選択しました。

将来的にはDockerなどでコンテナ化されており、ローカル環境で開発可能であることが理想ではあると思いますので、コンテナを利用した開発環境の準備を進めています。

💡 ラクスルは2013年に作成されたシステムを、PHPからRailsへの移行作業を行いながら開発・運用しています。PHPとRailsのハイブリッド構成でnginxでルーティングされている箇所も多いため、Docker環境の構築が難易度の高いものとなっています。ローカル環境の代わりとして、1人1台の個人開発用EC2が提供されていますが、今回はデータ投入の手間などを考えテスト環境を使用しました。

まとめ

印刷ECは結構ニッチな領域で、raksul.comは長年保守されたシステムということもあり、聞かなければわからないこともたくさんあるので素直に聞くことが大切だと思います。

ラクスルは企業のカルチャーとしてCo-Operationが浸透しており、コミュニケーションの取りやすい環境にあると感じました。ただ、やはり人となりがわかっていない人とリモートでコミュニケーションをとり、仕様を詰めていくのはエネルギーのいることでした。

今後は出社日を有効活用し、リアルで熱く議論してチームの交流を推進していきたいです 🔥

ラクスルには出社日にチーム間の交流を促進するための取り組みとして、ドリンクやケータリングが提供されています。

写真はいの一番にケータリングに群がるPBUのメンバーたち。

ラクスルではエンジニアを募集しています!

https://recruit.raksul.com/career/engineer/

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

https://qiita.com/advent-calendar/2021/raksul

スピードチェック入稿にシールを対応させた話

はじめに

はじめまして、 ラクスルのフロントエンドエンジニアの原口です。 2020年4月に新卒第5期として入社して、入社後から今現在まで DTP チームに所属しています。

今回は、 DTP チームで開発しているデータチェック基盤の紹介と、新たにシールに対応できるように機能の追加を行った話をしたいと思います。

スピードチェック入稿とは

ラクスルでは、ファイルのアップロードと同時に自動でチェックを行い、そのファイルを印刷用に最適化する「スピードチェック入稿」というサービスを提供しています。具体的には、フォントに問題がないか?画像が壊れていないか?などのチェックと、可能であればその自動修正を行います。

スピードチェック入稿による恩恵として以下が挙げられます。

  • より早くユーザにチェック結果を届けることができる
  • 基本的なデータチェックを自動で行うことで、オペレータが高度なデータチェックに注力できる

オペレータはより多くの注文に対してデータチェックを行うことが出来るため、データチェックの平均的な待ち時間の短縮やデータチェックの品質の安定化に、欠かせない機能となっています。

シールという商材について

既にラクスルではチラシや冊子、名刺といった注文数の多い商品はスピードチェック入稿に対応していました。

今回紹介するシールは、チラシや冊子などのメジャーな商品に劣らないデータチェック件数を誇りながら、オペレータによる手動チェックにおいて次のような課題がありました。

  • 注文の縦横のサイズと印刷データの縦横のサイズが一致していないことが多い
  • データチェックを一度で通過できる割合が 20~30% と低い
  • 修正が必要な印刷データの場合、ユーザはオペレータとメールでコミュニケーションする必要がある

印刷データに関する問題をユーザに自己解決してもらうことでこれらの課題を解決するシールスピードチェック入稿を開発しました。

シールスピードチェック入稿について

ファイルアップロード

まずはじめに、手持ちのファイルを選択します。

注文の縦横のサイズが対応している場合はラクスルの提供しているオンラインデザインも利用することが出来ます。

アップロード画面

データチェック

アップロードされたファイルは自動的にトリミングされて、印刷の仕上がりプレビューが表示されます。問題がなければこのまま入稿確定まで進むことが出来ます。

アップロードと同時にデータチェックが自動で開始します

印刷の仕上がりプレビューが表示されます

調整が必要なファイル

シールはチラシや冊子などの定形の商品と異なり、様々な注文の縦横のサイズに対して様々な種類のファイルがアップロードされます。たとえば、

  • ロゴデザインのような余白が大きい印刷データ
  • 注文サイズの縦横比と印刷データの縦横比が異なる印刷データ

といったケースが考えられます。

このようなファイルをアップロードした場合、下記のような仕上がりプレビューが表示されます。

印刷したいロゴが見切れてしまっている状態

この問題を解消するため、エディタ機能を実装しました。 プレビューに問題があった場合「仕上がりを調整する」ボタンでエディタを開き、手動でトリミングの位置を調整することが出来ます。

エディタの機能

「縦幅に合わせる」「横幅に合わせる」を選択することで、簡単に印刷データの大きさを調整できます。

位置や大きさが期待通りでない場合はさらに調整できます。

大きさの自動調整

調整後は仕上がりプレビューにその調整が反映され、ユーザは再度仕上がりを確認できます。

大きさと位置の手動調整

フロントでこだわったこと

フロント側の実装にあたり、データチェック業務に携わっているオペレータの方にユーザの印刷データの特徴のヒアリングを行い、機能のあるべき形について議論しました。

例えば、当初は UI を極力シンプルにし、ユーザには画像の位置と大きさの細かい調整してもらうことを想定していたため、画像の右下に一つだけツマミを配置し、拡縮を調整する設計となっていました。 ところがユーザのファイルを見ていくと、A4サイズのデータの端にロゴのみがあるような印刷データが一定割合存在したので、画面を大きく使って操作できるような UI が必要であることが分かりました。 そこで、四隅に拡縮を調整するアイコンを置き、どんな印刷データが来ても WEB 上で調整できるようにしました。

また、リリースに向けてフロントエンド開発に携わっていないメンバーを呼んでのレビューを定期的に行いました。 普段操作し慣れている自分が気づかない問題点をあげてもらい、 UI の調整を行いました。

最後に

シールスピードチェック入稿は10月にリリースしたばかりですが、より使いやすいプロダクトを目指して機能開発を行っていきます。

ラクスルでは「仕組みを変えれば、世界はもっと良くなる」のビジョンのもと、産業構造の変革にチャレンジしています。

エンジニアも絶賛募集中ですので、ご興味をお持ちいただけましたらぜひお声がけください!

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

こんにちは、ラクスル事業本部 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はよしなにやってくれるので非常に助かる反面、意識していないとハマるポイントもあります。サービス自体が比較的新しく現時点ではそこまで情報が多いわけではないので、この記事が何かのお役に立てば幸いです。

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