Gaudiy Tech Blog

Gaudiyの技術、開発組織、カルチャーについてお伝えするブログです

GraphQLにおけるエラーハンドリングの実践

f:id:hanahanayaman:20220217214432p:plain

こんにちは。エンタメ領域のDXを推進するブロックチェーンスタートアップ、Gaudiyでエンジニアをしている高島(@takashima_katsu)です。

Gaudiyでは現在、BFFレイヤとしてGraphQLサーバを利用しています。導入してから1年以上が経ちますが、スキーマ駆動開発はDXの向上につながっていると実感しています。(以下のブログが詳しいです。)

techblog.gaudiy.com

今回は、GraphQLの利点を活かしたエラーハンドリングの方法について、Gaudiyでの実践をもとに書いてみたいと思います。エラーハンドリングの実装について課題感のある人や、現在GraphQL Errorsを使っている人に、ぜひ読んでいただけると嬉しいです。

1. エラーハンドリングとGraphQL

エラーハンドリングとは、プログラム実行時にエラーが生じた際に、すぐにその実行を終了させず、あらかじめ用意しておいた処理を行うことです。これをすることで、意図しない構造のデータが保存されたり、異常終了してしまう事態を防ぎます。

Gaudiyでは、GraphQLでのエラーハンドリングを行っており、そのベストプラクティスを探ってきました。

GraphQLの特徴は、データをモデル化し、スキーマとして定義することです。これによって、APIドキュメントなどを別途作成せずとも、クライアントがイントロスペクションを通じてスキーマの詳細を知ることができ、必要な情報を要求することができる、というメリットがあります。

GraphQLエラーハンドリングにおける一般的な手法としては、以下の errors エントリーにエラーの詳細を含める、GraphQL Errorsがあると思います。

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["hero", "heroFriends", 1, "name"],
      "extensions": {
        "code": "CAN_NOT_FETCH_BY_ID",
        "timestamp": "Fri Feb 9 14:33:09 UTC 2018"
      }
    }
  ]
}

これは GraphQL SpecのErrorsセクション から持ってきたものです。このエラー表現を、後述するエラー表現と区別するために、便宜上「トップレベルエラー」と呼びたいと思います。

トップレベルエラーは、GraphQL Specでも説明されていたり、GraphQLサーバの実装でよく使われる Apollo Server のドキュメントでも紹介されているので、よく利用されている表現だと思います。

しかし、ここで考えていただきたいのですが、これはGraphQLの利点を活かすことができているのでしょうか?

今回はその課題提起と、解決策としての実装方法について紹介したいと思います。

2. GraphQL Errorsにおける課題

GraphQLの利点は、先述の通り、スキーマとして定義することで、クライアントがイントロスペクションを通じてスキーマの詳細を把握できる点にあります。

ですが、トップレベルエラーには、このスキーマがありません。そのため、クライアント側がどういったエラーがあるかを知ることができなかったり、型の自動生成もできなかったりして、別途、ドキュメントの作成やコミュニケーションコストが発生してしまいます。

また実際に運用していく中で、エラーの追加や変更に気がつかず、フロントで適切なエラーフィードバックを出せなくなってしまったり、そもそもエラーによって細かくフィーバックを出すことが億劫になってしまい、抽象度の高いエラーフィードバックを出してしまうこともありました。

結果として、Gaudiyが大事にしている『Fandom』ではない体験の提供につながってしまったり、DXも悪くなってきていると感じていました。

また、 extensions エントリーなどでエラーを拡張したりと便利なことも可能ですが、これもスキーマ外で定義することになるため、同じように別途ドキュメントの作成が必要でした。

3. GraphQLエラーハンドリングの実践

こうした課題に対して、エラーもデータと同じようにモデル化し、スキーマとして定義する方法を取り入れていきました。このスキーマでのエラー表現を、トップレベルエラーと区別するために、便宜上「スキーマエラー」と呼びます。

ここからは、Gaudiyでは実際、どのようにスキーマエラーを実装しているのかについて説明していきます。

3-1. エラーの分類

まずは、エラーを分類します。エラーの種類によっては、今まで通りトップレベルエラーを使った方が良いケースもあり、Gaudiyでも多くのエラーではトップレベルエラーを利用しています。

具体的には、「例外エラー」と「ドメインエラー」の2つに分類しており、前者ではトップレベルエラーを、後者ではスキーマエラーを使用しています。この分類は、GraphQLの作者の1人であるLee Byronも、いくつかのissuesで触れています。

GraphQL errors encode exceptional scenarios - like a service being down or some other internal failure. Errors which are part of the API domain should be captured within that domain.

https://github.com/graphql/graphql-spec/issues/391#issuecomment-385553207

The general philosophy at play is that Errors are considered exceptional. Your user data should never be represented as an Error. If your users can do something that needs to provide negative guidance, then you should represent that kind of information in GraphQL as Data not as an Error. Errors should always represent either developer errors or exceptional circumstances (e.g. the database was offline).

https://github.com/graphql/graphql-spec/issues/117#issuecomment-170180628

「サーバが落ちている」などのシステム系のエラーは「例外エラー」に、「認証情報がない」などのドメインに関するエラーは「ドメインエラー」に分類するようにします。

3-2.ドメインエキスパートへのヒアリング

スキーマエラーの対象となる「ドメインエラー」は、その名の通り、ドメイン知識として扱います。

そのため、どのようなエラーが考え得るかについて、ドメインエキスパートへのヒアリングを通じて、チームで共有することが大事です。 Gaudiyの場合は、実例マッピングや受け入れ基準設定のときに、どういった失敗ケースがあるのかを洗い出しています。

その後、 どのようなフィードバックを出すのがユーザー体験として良さそうかを、CSやデザイナーと議論しながら進めています。

f:id:hanahanayaman:20220217211823p:plain
実際のチケット

これは、最近「シリアルコードを入力してNFTを受け取れる」という機能を実装した際の、実際のチケットです。実例マッピングをして、受け入れ基準の設定まで行いました。(Gaudiyではこのように、ユーザーストーリーベースでチケットに書くようにしています。)

どういった失敗ケースがあるのかをチケットの受け入れ基準に書いていますが、それをそのままスキーマで定義します。

"""
エラー: 該当しないシリアルコードの場合
"""
type CheckSerialCodeNotApplicable {}

"""
エラー: 既に使用されているシリアルコードの場合
"""
type CheckSerialCodeAlreadyUsed {}

"""
エラー: シリアルコードの入力回数が上限を超えている場合
"""
type CheckSerialCodeUsageLimitExceeded {}

3-3. Union を使った Result 型の作成

先ほど定義したスキーマをもとに、Result型を作成し、オペレーションタイプの返り値として返す方法を採用しています。

こちらの方法は 『200 OK! Error Handling in GraphQL』 で詳しく説明されているので詳細は省きますが、以下のように定義することができます。

type Mutation {
  """
  シリアルコードの入力チェック
  """
  checkSerialCode(serialCode: String!): CheckSerialCodeResult!
}

union CheckSerialCodeResult =
    CheckSerialCodeSuccess
  | CheckSerialCodeNotApplicable
  | CheckSerialCodeAlreadyUsed
  | CheckSerialCodeUsageLimitExceeded

"""
成功
"""
type CheckSerialCodeSuccess {}

"""
エラー: 該当しないシリアルコードの場合
"""
type CheckSerialCodeNotApplicable {}

"""
エラー: 既に使用されているシリアルコードの場合
"""
type CheckSerialCodeAlreadyUsed {}

"""
エラー: シリアルコードの入力回数が上限を超えている場合
"""
type CheckSerialCodeUsageLimitExceeded {}

この方法は、複数のエラーを同時に返せないなどの制約はありますが、シンプルな実装になっています。

また、複数のエラーを同時に返したい場合などは、『A Guide to GraphQL Errors』 の Error Union List の方法が参考になると思います。

mutation Mutation($serialCode: String!) {
  checkSerialCode(serialCode: $serialCode) {
    ... on CheckSerialCodeSuccess {

    }
    ... on CheckSerialCodeNotApplicable {

    }
    ... on CheckSerialCodeAlreadyUsed {

    }
    ... on CheckSerialCodeUsageLimitExceeded {

    }
  }
}

このようにスキーマエラーを使うことで、フロントはスキーマの詳細を知ることができ、 __typename の分岐でエラーフィードバックのハンドリングを行うことができるようになります。

4. まとめ

この記事では、Gaudiyで実践している、GraphQLのエラーハンドリングの方法についてご紹介しました。

エラーを「例外エラー」と「ドメインエラー」に分類し、ドメインエラーをスキーマとして定義することで、 DXの良いハンドリングを行うことができます。ドメインエラーはドメイン知識とイコールなので、ドメインエキスパートへのヒアリングを通じて洗い出していくことが大事です。

GraphQLの特性を活かしたエラーハンドリングの仕方として、ご参考になれば嬉しいです。この辺り興味ある方いれば、ぜひお話ししましょう!

https://meety.net/matches/YEieGYUZDYhr

Gaudiyの技術スタックやその選定思想については、こちらの記事をご参考ください。

techblog.gaudiy.com

エンジニアがCSチームとのコラボレーションで大切にしていること

f:id:hanahanayaman:20220207120112p:plain

こんにちは!エンタメ領域のDXを推進するブロックチェーンスタートアップ、Gaudiyでエンジニアをしている永井(@sho0910K)です。

Gaudiyではここ数ヶ月、CSチームとエンジニアチームのコラボレーションがうまく回り始めていると感じています。

GaudiyにおけるCSチームは、Gaudiyが提供するファンコミュニティでユーザーさんのサポートや体験づくりを担当しているチームです。 社内では「コミュニティチーム」と呼んでいますが、一般的にはCS(カスタマーサポート、カスタマーサクセス)チームが近いと思いますので、今回は「CSチーム」と呼ばせていただきます。

先日公開した2022年の抱負blogにある「プロダクト主導型組織」としてはまだまだ改善すべきところは多いですが、以前に比べればCSチームとエンジニアチームのコラボレーションは多くなってきており、CSチームを通してエンジニアチームにもユーザーさんの声がよく届くようになってきていると感じています。

そこで今回は、CSチームとうまくコラボレーションするために、エンジニアとして大切にしていることをご紹介したいと思います。

エンジニアとCSチームの連携がうまくいっていないと感じている方、プロダクトの改善がユーザーさんに届いているか不安に思っている方の改善の参考になれば幸いです。

1. CSチームとのコラボレーションで大切にしていること

より良いプロダクト開発を進めるためには、CSチームとのコラボレーションは不可欠です。その連携において、エンジニアとしては次のことを大切にしています。

  1. フィードバックをプロダクト目線で捉える
  2. ユーザーさんにプロダクトの改善を届ける
  3. エンジニア視点でのみ話さない

1-1. フィードバックをプロダクト目線で捉える

CSチームからはユーザーさんの率直な意見がたくさん共有されますが、これを受け止める際には「プロダクト目線」を大切にしています。

Gaudiyの提供するコミュニティアプリは、共通基盤をもつワンプロダクトですが、IPごとに別々のファンコミュニティとして提供されています。 そのため改善に関しては、特定のコミュニティでのみ考えるのではなく、コミュニティアプリというプロダクト全体に関わる改善として考えています。

そこで大切なのは、フィードバックとして挙げられた要望の背景をエンジニアとしても理解することです。 背景を理解した上で、最適な設計に落とし込めるようにPdM・エンジニア含めて議論しています。

1-2. ユーザーさんにプロダクトの改善を届ける

フィードバックを元にプロダクトの改善を行ったら、その改善をユーザーさんにきちんと届けることが大切です。 プロダクトの改善は、困っていたユーザーさんに改善された旨が伝わり、再度使っていただいた上で実際に改善されたとわかっていただくまでがゴールだと考えています。

これにはCSチームとのコラボレーションが不可欠で、「今回のリリースでは何を改善したのか」をCSチーム宛に連携することで、ユーザーさんにも改善の旨を伝えてもらっています。

1-3. エンジニア視点でのみ話さない

僕の所属するエンジニアチームでは、週の初めに一週間分の開発スプリントを決めていますが、このミーティングにはCSチームも参加しています。実際のユーザーさんの投稿を参考にして、優先度や対応する項目を議論しています。

この議論の際には、エンジニア視点だけで話さずに、実際にコミュニティを使う側を想定して話したり・技術的な用語を噛み砕いて話したりしています。

2. 以前はCSチームとのコラボレーションはうまくいっていなかった

そもそもの背景として、半年ほど前はCSチームとエンジニアのコラボレーションがうまく回っていませんでした。 具体的には、以下の課題を抱えていました。

  1. ユーザーフィードバックの優先度があがらない
  2. CSチームから声があがりづらくなる
  3. フィードバックに対応するエンジニアが偏る
  4. プロダクトの改善がユーザーに届いてない

2-1. ユーザーフィードバックの優先度があがらない

Gaudiyはまだまだリソースの多くない組織です。そのため、事業的な開発リソースと運用上でてくる改善や問題への対応のリソースの配分において、どうしても事業進捗に関わる部分の開発のほうが優先されている時期がありました。そんな中では、せっかくCSチームからあがった改善の対応に関しても優先度が上がりづらくなっていました。

2-2. CSチームからの声があがりづらくなる

開発のスプリントとして優先度が落ちてしまうと、スプリントを決める会において、CSチームから発言や改善要望がなかなかあがりづらい状況になっていました。実際、声をあげたとしても受け入れられるかわからないという感覚をCSチームに与えてしまっていたと思います。

2-3. フィードバックに対応するエンジニアが偏る

CSチームから声が上がりづらい状況になったために、突発的なフィードバックに対応するエンジニアも限られていました。当時はエンジニアチームとCSチーム間のコラボレーションも、限られたメンバーで行うなどの偏りがあったため、そこに関わっているメンバーしか自発的に動かないような状況でした。対応をお願いしたとしても「やらされている感」を感じさせてしまっていたと思います。

2-4. プロダクトの改善がユーザーに届いてない

さらに、フィードバックを受けてプロダクトに反映し改善版リリースを行ったとしても、それがユーザーさんに届いていないことがありました。 CSチームがその改善がリリースされたことに気づいていない、ユーザー告知するリリース内容から漏れてしまうといった問題がありました。

3. 改善のきっかけは率直なフィードバックを求めたこと

そんなモヤモヤした状況でしたが、その流れが吹っきれたのは、取締役でPdMを担う後藤からの「CSチームは率直にユーザーさんの声をエンジニアチーム宛に伝えた方がいいと思います」という一言でした。

僕自身もここにモヤモヤを感じていたため、すぐさま賛同しぜひにと相槌を激しく打ったものです。 そしてこの日を境に、Slackの#mimamoriチャンネルから来る通知の量が格段に多くなりました。

4. CSチームとのコラボレーションで実施してること

  1. ラフにユーザーさんの報告や改善を投稿できる場作り
  2. リリース内容の共有
  3. Whyの明確化

4-1. ラフにユーザーさんの報告や改善を投稿できる場作り

CSチームを通してのユーザーさんからの報告は気軽さを優先して、Slackのmimamoriチャンネルに投稿してもらうようにしています。 投稿のフォーマットも現在は設けておらず、かなりラフに投げていただいています。

f:id:hanahanayaman:20220207120042p:plain
#mimamori_改善報告チャンネルでの投稿

この投稿に特定のスタンプを付けることで、Shortcutというチケット管理ツールに自動登録されるようにしており、バックログリファインメントの際に確認できるようにしています。

4-2. リリース内容の共有

リリース内容の共有は、Slackのワークフローを使って情報連携を行っています。

f:id:hanahanayaman:20220207114254p:plain
リリース内容や開発担当者をSlackで連携

リリース内容を確認できるプレビュー環境も共有することで、今回のリリースでどのような内容が更新されるのかを、CSチームのメンバーが実際のプロダクトを触りながら確認できるようにしています。

4-3. Whyの明確化

CSチームから改善要望や施策の相談があがった際には、背景を理解することを意識しています。 その改善や施策が求められている背景は何なのか、一番良い解決策やプロダクトの将来性も含めて議論できるようにしています。

これに関しても、Slackの投稿スレッドでCSメンバーとエンジニア、そしてPdMを交えて活発にやり取りしています。

f:id:hanahanayaman:20220207115050p:plain
実際にWHYを確認するやり取りの一部

5. CSチームとのコラボレーションからの学び

以前はCSチームからの報告に対応するエンジニアは限られていましたが、上述したような工夫をしたことで、これまで参加していなかったエンジニアもCSチームとの会話に入ってきたり、報告をキャッチアップしてWhyを聞きに行ったりと、とても自律的に動くメンバーが増えてきたと感じています。

これはCSチームのメンバーが率直にユーザーさんのフィードバックを届けてくれるようになり、Slack上でのフィードバックや改善に対する議論が盛んになったからだと思います。

6. さいごに

Gaudiyのバリューのひとつに「Fandom」という考えがあります。これはあらゆるステークホルダーに最高のファン体験を届ける、というものです。

まだまだプロダクト主導型組織として足りてないところは多いと思いますが、ひとつでも多くユーザーさんにFandomを届けられるように、よりエンジニアチームとCSチームのコラボレーションを濃くしていきたいと思っています。

Gaudiyで一緒にユーザーさんにFandomを届けたい方(エンジニアやカスタマーサクセス問わず)や、CSチームとの連携で同じような課題感を持っているエンジニアの方、ぜひお話しましょう!

meety.net

Gaudiyの技術スタックやその選定思想については、以下記事をご参考ください。

techblog.gaudiy.com

システムの変動性の特定とアーキテクチャ設計

f:id:hanahanayaman:20220128221846p:plain

こんにちは。エンタメ領域のDXを推進するブロックチェーンスタートアップ、Gaudiyでエンジニアをしている勝又(@winor30)です。

Gaudiyでは、アイドル、ゲーム、マンガなどの様々なIP(知的財産権を有するコンテンツ)をベースにしたファンコミュニティを提供し、そのコミュニティ上で様々なサービスが利用できるような "スーパーアプリ" のようなプロダクトを開発しています。

このような特性のプロダクトづくりにおいて重要なのは、特定のIPコンテンツに特化させずに、どうやってコミュニティ上のサービスをつくっていくのか? という点です。

そこでGaudiyでは、よりスケーラブルでレバレッジの効いた開発をするため、ソフトウェアの原則を重視しながらも、コラボレーションを通じてプロダクトビジョンを捉えることによって、正しい技術的な意思決定をしていこうという考え方があります。

今回は、上述したような意思決定プロセスを、実際に開発した様々なデジタルアイテムの購入システムを例に説明していこうと思います。事業にレバレッジをかけることができるような拡張性のあるソフトウェア開発の参考になれば嬉しいです。

1. レバレッジの効いた開発に必要なことは?

最も大事なことは、プロダクトビジョンを捉え、将来の拡張性を予想することです。

一般的に、将来の拡張性を予想することはYAGNIの精神に反するため、XP的な考え方からするとアンチパターンのように思われます。しかし、投資的な開発を実現できるとのちの追加実装が楽になり、事業進捗を加速させることができます。

そこでGaudiyでは、エンジニアだけでなく、PdM、BizDev、コミュニティマネージャーなど様々なステークホルダーからプロダクトに関するビジョンや将来の方向性を徹底的にヒアリングし、それらを設計に落とすようにしています。

1-1. ヒアリングの方法

ヒアリングの方法は、できるだけコラボワーク(協働できる作業)を取り入れて、ステークホルダーの考え方やメンタルモデルをつくることに注力しています。このコラボワークは、現在だとストーリーマッピングやDDDによるドメインモデルづくりなどがあります。

(GaudiyのDDDの取り組みについてはこちらの記事が詳しいです。)

techblog.gaudiy.com

このときに様々なことをヒアリングするのですが、最も大事だと考えているのは、プロダクトのWHYと将来性をヒアリングしていくことです。この部分は後述する「カプセル化すべきシステムの変動性」に直結していく部分になるので、どういう変化があるのか? というところを様々なステークホルダーにヒアリングすることが重要です。

また、聞き方として気をつけていることとしては、以下の点があります。

  1. ステークホルダーが使った単語・言葉をそのまま使う
  2. 具体例を聞いたあとに抽象的な話を聞く

まず1点目については、ステークホルダーがイメージするモデルを、聞き手のバイアスなしでそのまま引き出すためです。相手が使った単語・言葉を聞き手が言い換えてしまうと少し誘導してしまう形になり、本来のメンタルモデルを汚してしまう恐れがあります。この考え方は「クリーン・ランゲージ」という書籍にある考え方で、どうやって相手のメンタルモデルを100%引き出し、バイアスなしで理解できるか? という方法になります。

この手法はコンサルタントやUXリサーチャーなどがよく使っているのですが、エンジニアのモデリングも本質的には同じだと考えており、相手のモデルを理解し、それをアーキテクトしていくことが良いシステムを作っていく上で大切だと考えています。ただ個人的にはバイアスなしにヒアリングを進めるのはかなり難しく、「こういうシステムになるだろうな…」と予想しながらヒアリングをしてしまうなど、認識の誤差が埋まらないケースなどもありました。

次に、具体例を聞いたあとに抽象的な話を聞くこともメンタルモデルの理解を深めるためのひとつの手段です。最初に同じように認知できやすい実際のケースを聞くことによって、その後の抽象的な概念を具体例と照らし合わせることにより、認識の誤差を減らしていくことができます。

1-2. カプセル化すべきシステムの変動性の導出

また、前述のヒアリングを通して「システムの変動性」を見つけることが、プロダクトにレバレッジを効かせるためには不可欠です。

この変動性とは、Righting SoftwareBuilding Microservices, 2nd Editionなどに書かれている、ビジネスドメインの境界を見つける手法の一つになります。

変動性をソフトウェアに適応するということは、変更される可能性がある領域を明確にし、その部分をサービスやシステムとしてカプセル化することで、その変化が他のシステムに影響を与えないようにすることを指します。

サービスの境界を見つける手法としては、DDDを利用して、Bounded Contextが境界になるやり方も存在するとは思います。ですが、変動性による分解を利用する方が、どういった変動領域から他のシステムを守りたいのか?という視点で境界を定められるので、より柔軟なビジネスドメインの境界を見つけることができる印象をもっています。

また個人的には、SOLIDの単一責任の原則と変動性のモチベーションがかなり近いと考えており、分解の手法としてはかなり有用なものだと考えています。

この変動性領域は「あとから変更できる」という意味合いではなく、「将来的にどういう変化をする可能性が実際にあるのか?」という点が大事です。そのために、PdMやコミュニティマネージャーにプロダクトビジョンをヒアリングしながら、「将来どういうことが行われるのか?」「この機能に対してどんなイメージをもっているのか?」などをエンジニアのバイアスなしにヒアリングしていき、どのような変動性があるのかを見極めていきます。

2. 様々なデジタルアイテムの購入に関する適用例

上記で説明したような変動性の導出を実際の機能開発で行ったので、そのプロセスや実際にやったことを説明します。

2-1. ヒアリングによる変動性の導出と技術的意思決定

f:id:hanahanayaman:20220130145151j:plain
デジタルアイテムの購入イメージ

今回開発した機能としては、様々なデジタルアイテムをクレジットカードで購入できる機能です。

この様々なアイテムとは、具体的に下記3つを購入できるようになっています。

  1. コミュニティ内で閲覧できるライブ配信のデジタルチケット
  2. コミュニティ内でデジタルアイテムがもらえるガチャを引くことができるガチャチケット
  3. コミュニティと連携している(Gaudiyが運営していない)ソシャゲのアイテム

これらのアイテムを、Gaudiyが提供しているコミュニティ内から同じようなフローで購入できるような機能を開発しました。

このプロジェクトで実際にステークホルダーに対するヒアリングを実施した結果、「購入条件の変動性」と「購入商品の変動性」が存在することがわかったため、この部分をカプセル化するようなモデリングの意思決定を行いました。

購入条件の変動性としては、コミュニティで販売するにあたって、コミュニティや外部アプリでの条件(ex. コミュニティレベルや外部アプリのアカウントを持っているか?など)がありました。この条件が増えていくことは、将来的にコミュニティで利用できる新しいエンタメの購買体験を作るというビジョンを持っていたため、必要があると考えました。

また購入アイテムの変動性は、販売するアイテムがコミュニティ内部のアイテムだけでなく、同一IPのソシャゲやECなどコミュニティ外のアイテムを購入できることもビジョンとしてあるため、アイテムが増えるという変動性から他のシステムを守りたいと考え、必要だと考えました。

2-2. Sagaパターン x Orchestrationで結果整合性を担保

f:id:hanahanayaman:20220128153040p:plain
Sagaパターンの正常ケースと異常ケース

変動性を導出した上で、今回は機能の特性上、どうやってアプリケーションとの整合性を担保するかを考慮する必要がありました。

一般的には、可能であれば整合性はDBのトランザクション等を利用してアトミックに行うのがよいとされています。

しかし、アイテムが外部のサービスの商品であったり、そもそも決済代行のAPIが外部のものを利用したりしていたため、今回は結果整合性を担保するような方針でシステムを作っていくことにしました。

そのため、マイクロサービスでの結果整合性を担保させるのに有用なパターンである、Sagaパターンを利用しました。結果整合性を担保したいワークフロー的な処理のどこかで失敗した場合は、全てのデータを元に戻すような補償トランザクションを送ることによって、結果整合性の担保を実現しています。

また、Sagaパターンを利用しつつ、OrchestrationとCoreographyの選択としてはOrchestrationを採用しています。

この意図としては、全体的な購入のワークフローにおいて、失敗したときに、直感的にロールバックを実行しやすく、シンプルな構成になりやすいためです。Coreographyの選択も社内で議論はしたのですが、最終的にピタゴラスイッチ的になり複雑化する懸念があったので、シンプルなアーキテクチャパターンの方を選択しました。

3. 実際の構成

3-1. アーキテクチャ

f:id:tkatsumat:20220131111529p:plain
実際のアーキテクチャ

基本的にupstream serviceとしてPaymentServiceがあり、downstream serviceとしてCheckService、GiftService、決済代行の外部APIが存在するようなアーキテクチャになっています。

ステータスの状態に関しても、どこで失敗したのかに関しては観測可能な状態になっているため、仮に結果整合性が担保できなかった場合でも、どこまでやり直せば良いのかがわかる仕組みになっています。

また、各サービスは購入のメインユースケース以外にも、クレカの登録や商品情報の表示、購入条件の表示などのユースケースに対しても利用されています。

3-2. ストラテジーパターンの利用

購入アイテムや購入条件の変動性によってチェックロジックが走る部分に関しては、ストラテジーパターンを利用し、インターフェースは共通にしながらも内部実装を種類ごとに分けていきました。

 

また、ソフトウェアの構成的にもストラテジーの選択と実行を分けて、より疎結合な設計にしています。

 

ストラテジーパターンを利用した意図としては、購入アイテムや購入条件の変動性をカプセル化したとしても、変動性による影響がソフトウェア内部で発生はするので、その影響を最小限に留めたかったためです。

この設計パターンを利用したおかげで、基本的には新しいものが追加された場合は、その実装クラスを選択するロジックとその実装クラスの内部ロジックを実装するだけでよくなり、より柔軟なソフトウェアアーキテクチャになりました。

4. まとめ

今回は実際にGaudiyで開発したデジタルアイテム購入の機能に関して、どんなところを気をつけながら事業のレバレッジを仕込めるようなものにしていったのかという点に関して説明しました。

事業を推進させるためのエンジニアの役割として、ステークホルダーのメンタルモデルを正しく探り、ソフトウェアの原則を正しく適用することによってレバレッジのあるアーキテクチャを作っていくことが、非常に重要だと個人的には考えています。

ただし、こういった取り組みはまだまだ試行錯誤している部分も正直あるので、こういった不確実な領域でアーキテクトをしていきつつプロダクトに影響を与えたい方がいれば、ぜひ色々議論していき、よりよいプロセスや原則を探っていきたいです!

meety.net

Gaudiyの技術選定とその思想については、以下の記事をご参考ください。

techblog.gaudiy.com

プロダクト主導型の組織をめざして(2022年の抱負)

f:id:hanahanayaman:20220117175240p:plain

こんにちは!エンタメ領域のDXを推進するブロックチェーンスタートアップ、Gaudiy共同創業者の後藤(@PTeamd)です。

Gaudiyは2018年5月に創業し、今年は5期目を迎える年になります。

創業当初からブロックチェーン技術を活用したプロダクト検証を行い、2020年からはSony Music社、集英社、アニプレックス社などの国内大手IPホルダーと協業。エンタメ業界の構造的な課題を解決するプロダクトを通じて、新しいファン体験を提供してきたGaudiyですが、2022年はさらに「PLG(Product-Led Growth)」(※)へと舵取りをしていきます。

今回のブログでは、その背景とGaudiyが今年注力することについてお伝えします!ぜひご一読ください。

※PLG…「プロダクトがプロダクトを売る状態(Product sells itself)」をめざす戦略

1. 創業時からめざすのは「ファン国家」の実現

2018年の創業時より、ファンの応援や創作といった熱量が適正に認められ、ファンに還元されるエコシステム「ファン国家」の実現をめざしてきました。

Gaudiyでは単にブロックチェーン技術をPoCで試すというやり方ではなく、トークンを使ったコミュニティプロダクトをファンに向けて提供することで、New Standardかつベストな体験を社会に普及する取り組みを進めてきました。

創業初期はブロックチェーンの顕在的なニーズが世の中にあまりなく、先行事例も少なかったため、PMFをめざす上で重要だったのは「いかに関係者に価値を理解してもらえるか」でした。

そこでまずは、クライアント企業に深く入り込み、個別の状況に対して理解と共感を深め、エンタメ企業に共通するペインを見つけながら、それを解決するプロダクトをつくる。そのプロセスが必要であり、意図的に「案件ベース」でのプロダクト開発を進めてきました。

具体的には、Sony Music社のデジタル声優アイドルグループ「22/7(ナナブンノニジュウニ)」や、週刊少年ジャンプの人気漫画「約束のネバーランド」など、大手IPホルダー(知的財産コンテンツを有する企業)との協業案件です。

その中で、ファンコミュニティサービスの開発・提供を行いながら、中長期的なファン国家のエコシステム構築をめざして、様々な”仕込み”を行ってきました。

例えば、そのひとつが「分散型ID(DID)」の開発です。ブロックチェーン技術を活用した独自のIDシステムを構築し、実際のコミュニティプロダクトにも組み込んでいます。

note.com

また、Gaudiyの経済設計顧問である慶大・坂井教授や、同じくコミュニティサイエンス顧問である早大・石川教授とともに、トークンエコノミーの経済設計などにも取り組んできました。

このように、エンタメ企業の課題を解決するソリューションをブロックチェーンベースで組みながら、新しい経済圏づくりに必要な研究と実装を行いつつ、SLG(Sales-Led Growth)での着実な成長を遂げてきました。

2. 昨年起きた市場の変化と「PLG」への転換

そして昨年、市場に大きな変化が起きました。

NFTを中心にWeb3.0が大きな注目を集め、世間からの認知度・関心度が一気に高まりました。ありがたいことに、Gaudiyも大手IPホルダーから数多くのお問い合わせをいただいています。

創業時からこのタイミングが来ることを信じ、案件ベースで様々な仕込みを行ってきたGaudiyにとって、2022年は勝負の年。今後大きく飛躍できるかどうかの転換点になります。

そのために注力していきたいのが「PLG(Product-Led Growth)」です。

f:id:hanahanayaman:20220117084942p:plain

SaaSプロダクトでよく聞く言葉ですが、良いプロダクトが次の顧客を呼び込むような、プロダクト主導型の事業成長モデルのことです。(PLGについて詳しく知りたい方はこちらの本がおすすめです。)

2022年は「ファンと共に、時代を進める。」というミッションに向けて、より多くのファンに「Web3.0の体験」を提供し、最高の体験を実現をめざします。

具体的にいうと、Gaudiyでは単にNFTを販売するのではなく、Non-Fungibleな体験を提供していきます。トークンエコノミーで最も重要とされる「コミュニティ」を形成し、そのコミュニティと従来は散らばっていた関連サービスをDIDで統合することで、ファンの活動に対して還元するエコシステムをつくります。

また、エンタメ企業の課題を解決する、IP独自のファンプラットフォーム「Gaudiy Fanlink」というプロダクトに全集中します。国内はもちろん、海内のIPコンテンツとそのファンに対しても最適な体験を一貫して提供することをめざします。

3. これからの「プロダクト主導型組織」について

PLG型で世界中のファン体験を前進させるために、組織全体としても、プロダクトに対してフルベットします。「Product-Led Organization(PLO)」という言葉もありますが、Gaudiyはプロダクト主導型の組織づくりに注力します。

プロダクト主導の成長・組織構築をしていくためには、ソフトウェアの開発だけでなく、ビジネス、コーポレートなどを含むすべての活動を、プロダクトビジョンへのコミットに紐付けて目標設定と戦略実行のできる体制が重要です。

その大方針として、以下3つに取り組んでいきます。

3-1. 全社でプロダクトをつくる

あらゆる活動を上位のプロダクトに紐付けて設計します。エンジニアリング、デザイン、ビジネス、採用、組織開発、広報、バックオフィスなど、あらゆる活動を個別最適化させずにプロダクト中心に組み立てることで、より良いプロダクトづくりをめざします。

例えば、これまでプロジェクトベースで動くことが多かったBizDevの活動も、いかにプロダクトの成功に紐付くアウトプットにつなげられるかを軸に進めていけるようにする。またtoC向けサービスであることから、プロダクトを触ったり、関連したプロモーションを見て興味を持っていただくことも多いため、採用・広報として伝えていきたいストーリーをプロダクト側でも汲み取り反映していく。

さらには、全社的に「プロダクトの成長」を目標にすると同時に、プロダクトサイドでは全ステークホルダーがプロダクトづくりを「自分ごと化」できるように、要望に共感し成果につながるよう支援することで、全員が一丸となってPLGにコミットできる体制をめざします。

3-2. 人間中心設計(HCD)を強化する

人間中心設計(Human Centered Design)とは、簡単に言うと「人のことを理解し、ユーザーにとって使いやすいシステムを設計する」ということです。 案件ごとに、個別のユーザーやクライアントに向けてプロダクトをつくることは、その要望も目標も個別の最適化が追求できたため、ある意味で対象への共感がしやすい側面もありました。

しかしながら、国内外のより多くのコンテンツとファンにプロダクトを提供していくと、汎用性をめざす必要性が出てきますし、関係者と直に接点を持てる度合いも制限されます。それにより、これまでよりも「共感」をベースとしたFandomな体験の実現が難しくなります。

そこで、より体系的な形でファンにとって最高の体験を作るために、共感をベースとしたプロダクト開発手法である人間中心設計を強化していきます。

3-3. プロダクトを作るように組織を作る

上記のようなプロダクト開発手法を、ソフトウェア開発だけでなく、組織も広義の”プロダクト”として、それぞれの手法を一般化して各所に取り入れていきます。

例えばチームトポロジーに代表されるように、カプセル化・抽象化・インターフェースの設計など、エンジニアリングの観点を組織開発にも取り入れて、組織フェーズごとに最適なアーキテクチャーをつくり続けます。

またUXデザインにおける調査・モデリングの手法を、エンジニアリングではDDDなどのバックエンドの設計手法に、採用ではEXの可視化・改善のために利用します。

さらにピープルマネジメントにおいて重要なコーチングの概念は、プロダクトマネジメントや自律分散的な組織マネジメント、カスタマーサポートなどコミュニティの運営にも共通のコミュニケーションスタイルを利用していきます。

4. おわりに

今回のブログでは、2022年の抱負として、PLG型の事業成長と組織づくりの方針をお伝えさせていただきました。

Gaudiyでは、ファンにとっての最高の体験を実現し、時代を進める取り組みをもっと加速させていくため、プロダクト中心組織を一緒に創りあげていきたいと思う方を全方位で募集しています。

職種や職務で分断された形ではなく、ビジネス・テクノロジー・ユーザーの3領域を横断してプロダクトを磨き続けることは、ある意味では個々の専門性に閉じて役割分担をするよりも大きな負担がかかり、難しいことです。

f:id:hanahanayaman:20220116220154p:plain

出典:The Product Management Triangle – Product Logic

ですが、まだ世の中にない世界観である「ファン国家」の実現に向けて、新しい概念や技術を取り込みながらプロダクト開発を進めるGaudiyにとっては、この形が必要不可欠だと考えています。

困難なチャレンジになるとは思いますが、プロダクト中心組織をつくり、2022年もビッグなIPと時代の先端をいく取り組みを進めていきます。

国内はもちろん、言語の壁を超えてグローバルで通用する突き抜けたプロダクトを生み出すことに興味のある方は、ぜひお気軽にご応募ください!ワクワクする未来を、共創していきましょう。

---

最後に宣伝させてください🙏 1月25日(火)19時〜、クラウドサインさんと一緒に「不確実性に向き合うプロダクトマネジメント」をテーマにしたウェビナーを開催します!Gaudiyの開発全般についてお話しするので、PdMの方はもちろん、エンジニアやデザイナーの方々もよければご参加ください。

bengo4.connpass.com

ほぼ全職種オープンしています。お気軽にご応募ください。

www.wantedly.com

いろんな職種のメンバーがMeetyをオープンしてますので、こちらからでも!

meety.net

借りたものはきっちり返す。技術的負債への向き合い方

f:id:hanahanayaman:20211224133024p:plain

はじめまして。エンタメ領域のDXを推進するブロックチェーンスタートアップ、Gaudiyでエンジニアをしている@kaa_a_zuです。

早速ですが、質問です。みなさんは、所属している組織のコードを誇りに思い、この先数十年間に渡って使い続けることができると確信していますか?

私は、この質問をされた場合、顔を背ける自信があります。今回は、私と同じようにこの質問に対して "YES" と答えることが出来なかった人たち、そして 「リファクタリングをしたい」と思っているエンジニアが在籍する組織の偉い人たち に読んでもらいたい内容を書こうと思います。

テーマは、技術的負債の返済方法と技術的負債をためない方法についてです。(かなり長いので、HOWだけ知りたい方は4章から読んでいただけたらと思います。)

1. 一般的な技術的負債とは

「負債」という言葉を、日々の開発ではよく耳にするかと思います。改めて、技術的負債とはなんなのでしょうか。

技術的負債というものは、1992年にWikiの開発者であるウォード・カニンガム氏によって使われた表現です。彼の言葉を引用すると、技術的負債は「借金」と表現できます。それも開発が進めば進むほど、利息が高くなる悪魔のような借金です。

Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object- oriented or otherwise.

初めてコードを出荷することは、借金をするようなものです。少しの借金は、書き直しですぐに返済される限り、開発を加速させます。オブジェクトは、この取引にかかるコストを許容範囲にしてくれます。危険なのは、借金を返せなくなったときです。正しいとは言えないコードに費やされた時間は、借金の利息としてカウントされる。オブジェクト指向であろうとなかろうと、統合されていない実装の負債によって、技術者組織全体が立ち行かなくなる可能性があるのです。

お金に余裕のない企業が国や金融機関から借金をして事業をするのと同じように、「余裕がない状態で、負債をしてでもサービスをつくり提供する」という意味が込められています。この意味を読み取ると、改めて技術的負債という表現は上手くできていると感じます。

しかし、エンジニアリングにおいて、技術的負債をためようと思ってためているチームは存在しないはずです。ではなぜ技術的負債がたまってしまうのか。技術的負債と借金が大きく異なる点は「借主が借りたことを知らない(気付かない)」ことだと私は思います。

もちろん、納期が近いなかでやっつけの開発をした場合には、負債がたまっていることを自覚しています。しかしながら、みなさんが既に経験をしているように、通常の開発においても技術的負債はたまっています。借りていたことに気がつくのは数日後かもしれないですし、数年後かもしれません。

そして非常に残念なことに、その負債に関連したコードを書けば書くほど利息がついてきます。気がついた時には、利子が複利になっており、返済額もとても大きくなっているかもしれません。取り立てをされることはないですが、寝れない日が続く可能性は高いはずです。

f:id:hanahanayaman:20211224110532p:plain

さまざまな技術的負債が存在しますが、まとめると以下4つに分類することができると思います。

  1. 影響範囲が大きく、目に見えるもの
  2. 影響範囲が小さく、目に見えるもの
  3. 影響範囲が大きく、目に見えないもの
  4. 影響範囲が小さく、目に見えないもの

次の章では、4種類の技術的負債がなぜ発生するのかについて、私の考えを示します。

2. なぜ技術的負債が発生するのか

4種類の技術的負債がたまる代表的な原因をそれぞれ挙げてみます。

※原因の大きさによって、生じる技術的負債の種類が変わることをご了承をいただきたく思います

f:id:hanahanayaman:20211224103307p:plain

1. 影響範囲が大きく、目に見えるもの

  • ビジネスプレッシャー…ビジネス的な観点ですぐにリリースする必要があり、設計やコードにおいて妥協せざるを得なかった。
  • 不十分な先行定義…時間短縮のために、要件がまだ定義されていない状況で開発を開始しなければならなかった。
  • 誤ったテックリード…十分に考えられていない指示が指揮系統のもとに伝わってしまった。

2. 影響範囲が小さく、目に見えるもの

  • 割れ窓理論…DRYでなかったり、直交性がなかったり、変数名が適当なコード、コード規約が守られていないコードが散乱していたため、同様のごみ(ひどいコード)が捨てられ、さらに汚くなってしまった。
  • ビジネス的柔軟性…機能が適切な粒度のモジュールになっていないため、ビジネス要求の変化に柔軟な対応を取れない状態になってしまった。

3. 影響範囲が大きく、目に見えないもの

  • 継続的な開発…プロジェクトの息が長い場合、利用しているコアなライブラリやソリューションが最適ではなくなってしまった。
  • コラボレーション不足…知識や決定事項が組織内で共有されておらず、エンジニアと他の部署での認識のずれが生まれてしまった。
  • 知識の欠如…その時点で在籍している開発者が、問題に対してのベストな解決策や綺麗なコードの書き方を知らなかった。

4. 影響範囲が小さく、目に見えないもの

  • 偶発的プログラミング…コードがたまたま上手く動いているが、なぜ動いているのかを説明することができない。または、データ構造やアルゴリズムについて深く考えることができていなかった。
  • 不十分なテスト…テストスイートがないため、迅速だがリスクの高い暫定的なバグ修正が行われた。
  • 属人化…(小さな組織では特に)知識が属人的になってしまい、負債かどうかの判断もつけにくい状態になってしまった。

これらの原因のうち、心当たりがあるものはありましたか?もしあった場合、それは悪いことではなく改善するチャンスだと私は思います。

3. 技術的負債がもたらす問題点

返済方法について考える前に一度立ち止まって、技術的負債の問題について考えてみます。私は、技術的負債がもたらす問題には、大きく分けて3つあると思っています。

3-1. バグの温床になる

他の部分に影響が出ないと思って書いたコードが、実は様々な部分に影響を及ぼしていた場合にバグが生じます。バグは、サービスのユーザーをイライラさせます。そして悪い評判が立ったり、遅延やセキュリティ問題が発生することは、サービスだけではなく会社に悪影響を及ぼします。

また、CSチームやQAチームのやることも増えるため、社内の環境も悪くなります。当然、エンジニアはそのバグの対処に時間を割かなくてはいけなくなります。該当コードを書いた人はすでに組織を去っているかもしれず、バグの温床になってしまいます。

3-2. 新しい機能をユーザーに届けることが出来ない

よくない設計をしていたが故に、想定していなかった修正をしなくてはいけなくなる恐れがあります。そうなると見積もりで引いていたスケジュールの間にギャップが生まれるため、機能のリリースが遅れます。結果的に機能を渇望しているユーザーの期待を裏切ります。

スケジュールが数日ズレるだけならまだ良いですが、内容によっては「現在の設計だったらこの機能を作ることは難しい」という結論に至る可能性があります。新たな機能が加わらないために飽きがきたユーザーは、そのサービスから離れていってしまいます。

3-3. DXが損なわれる

思いもよらぬ様々なバグを生じさせた過去があったり、ノンリーダブルなコードを見ていると、コードを書く前に勇気をふり絞らないといけなくなります。また、新しいコードを書くために、多くの既存コードを読む必要がでてきます。

最終的に、離職率の上昇やエンジニア採用の成功率低下にもつながる可能性もあります。ひどい作業を好んで取り組みたい、引き継ぎたいと考えるエンジニアはかなり少数なはずです。

…いかがでしょうか?「技術的負債を甘くみていた」と思ってくれた方がいたら嬉しいです。

以上、技術的負債がどういう時に発生して、何が問題であるのかについて説明をしてきました。ここまで読んでくださった方は、おそらく技術的負債を抱えている人だと思います。大変お待たせしました。

次の章では、技術的負債の返済方法について、私の考えを示します。

4. 技術的負債の返済方法

もしも、読んでくださっている方の中に「海老で鯛を釣る」ことが好きな方がいたら、非常に残念なお知らせをしなくてはいけません。

人生と違って、宝くじや玉の輿に乗って大逆転をすることができないのがこの世界です。

また、目に見えない負債を返済することもできません。私たちにできることは、目に見える負債を減らすことと、目に見えない負債を少なくすることの2つだけです。

先ほど「2. なぜ技術的負債が発生するのか」の章で、4種類の技術的負債における代表的な発生原因を挙げました。それぞれの原因を潰すことができれば、返済をする、または返済額を減らすことが可能です。返済が簡単な順で見ていきます。

f:id:hanahanayaman:20211224115129p:plain

4-1. 影響範囲が小さく、目に見えるもの

まず、影響範囲が小さく、目に見えるものが最も簡単です。その発生原因としては「割れ窓理論」と「ビジネス的柔軟性」がありました。 それぞれの返済方法には、以下が挙げられると思います。

<割れ窓理論>

割れ窓理論…DRYでなかったり、直交性がなかったり、変数名が適当なコード、コード規約が守られていないコードが散乱していたため、同様のごみ(ひどいコード)が捨てられ、さらに汚くなってしまった。

  • コード規約ツールの利用
  • フォーマットの自動化
  • コードレビュー
  • CIで規制
  • 割れた窓を見つけた時に直す、もしくはチケットを切る

<ビジネス的柔軟性>

ビジネス的柔軟性…機能が適切な粒度のモジュールになっていないため、ビジネス要求の変化に柔軟な対応を取れない状態になってしまった。

4-2. 影響範囲が小さく、目に見えないもの

次に、影響範囲は小さいけれど、目に見えないものです。その発生原因としては「偶発的プログラミング」「不十分なテスト」「属人化」がありました。それぞれの返済方法には、以下が挙げられると考えます。

<偶発的プログラミング>

偶発的プログラミング…コードがたまたま上手く動いているが、なぜ動いているのかを説明することができない。または、データ構造やアルゴリズムについて深く考えることができていなかった。

  • 利用しているアルゴリズムとオーダー(O)を意識
  • 劣化が起きていないかCIでモニタリングを行う
  • TDD
  • コードレビュー

<不十分なテスト>

不十分なテスト…テストスイートがないため、迅速だがリスクの高い暫定的なバグ修正が行われた。

  • テストを書く
  • テストカバレッジをCIで規制

<属人化>

属人化…(小さな組織では特に)知識が属人的になってしまい、負債かどうかの判断もつけにくい状態になってしまった。

  • 社内勉強会
  • ドキュメント作成の義務化

4-3. 影響範囲が大きく、目に見えるもの

次に、影響範囲は大きいけれど、目に見えるもの。この発生要因としては「ビジネスプレッシャー」や「不十分な先行定義」「誤ったテックリード」がありました。それぞれの返済方法には、以下が挙げられると思います。

<ビジネスプレッシャー>

ビジネスプレッシャー…ビジネス的な観点ですぐにリリースする必要があり、設計やコードにおいて妥協せざるを得なかった。

この原因はエンジニアだけでは絶対に解決できません。ビジネスサイドの技術的難易度や技術的負債への理解と、ビジネスサイドとエンジニアサイドの心理的安全性を高める日々のコミュニケーションが必要です。 その上で、以下の方法があります。

  • ビジネス要件のうち落とせるものがないかを確認
  • 生じた負債はすぐにチケットを切る
  • アジャイル開発をしている場合は次スプリントに負債返済を入れる

<不十分な先行定義>

不十分な先行定義…時間短縮のために、要件がまだ定義されていない状況で開発を開始しなければならなかった。

  • 曳光弾の利用
  • 使い捨て前提のコードを利用するプロトタイプの作成

<誤ったテックリード>

誤ったテックリード…十分に考えられていない指示が指揮系統のもとに伝わってしまった。

  • キックオフミーティングや定期的なミーティングでその指示について議論する
  • (全開発者が意見を言えるように)開発者がただの作業員だと思わないような環境づくりを行う

4-4. 影響範囲が大きく、目に見えないもの

さいごに、影響範囲が大きく、目に見えないという返済が最も難しいもの。この発生原因には「継続的な開発」「コラボレーション不足」「知識の欠如」がありました。それぞれの返済方法としては、以下が挙げられると思います。

<継続的な開発>

継続的な開発…プロジェクトの息が長い場合、利用しているコアなライブラリやソリューションが最適ではなくなってしまった。

  • 定期的にライブラリをアップデートする
  • ライブラリアップデートの自動化
  • 技術アンテナを高く持ち、日頃から新しい技術を試す機会を設ける

<コラボレーション不足>

コラボレーション不足…知識や決定事項が組織内で共有されておらず、エンジニアと他の部署での認識のずれが生まれてしまった。

  • 勉強会を開く
  • デザインコラボレーションの機会を設ける

<知識の欠如>

知識の欠如…その時点で在籍している開発者が、問題に対してのベストな解決策や綺麗なコードの書き方を知らなかった。

  • 既存の類似サービスの真似をする
  • 先に利用する技術についての勉強会を行う
  • 知見を持つ技術顧問を雇う

上記のそれぞれに対する解決方法を用いることで、いくつかの原因を潰すことができると思います。次の章では、これらの解決策をふまえて私たちがどのような取り組みをしているのかについて紹介します。

5. Gaudiyの技術的負債に対する向き合い方

ここからは弊社が技術的負債とどのように向き合っているのかについて、いくつかの事例をご紹介しようと思います。

はじめに、弊社はWebアプリケーションを提供しています。メインのリポジトリは2つで、それぞれがモノレポの形を取っており、フロント, BFF, 複数のバックエンドサービスが管理されています。さらに興味がある方はこちらの記事をご覧ください。

5-1. 技術的負債を解消する取り組み

5-1-1. ソリューションの乗り換え

私たちのアプリケーションには、WindowAとWindowBでリアルタイムなやり取りをしなければならない仕様があります。これを実現するために、当初は window.postMessage() を1年近く利用し、うまく動いていました。ところがある日、それが負債であることに気がつきました。

この負債は、前章までに挙げた「影響範囲が大きく、目に見えない技術的負債」に当たります。感覚としては、ある日郵便受けを見ると、数千万円と書かれた連帯保証請求書が届いている感じです。当然びっくりしますね。

この負債に気がついた時に、問題や影響箇所の詳細について調査し、今乗り換えるべきかどうかをプロダクトオーナーを含めて相談しました。そして返済をするべき負債と決定したものの、どのようすれば返済ができるのかがすぐにはわかりませんでした。

ここで用いた方法が「知識の欠如」で挙げた「既存の類似サービスの真似をする」でした。幸いなことに、私たちが実現をしようとしていたタブ間通信と非常によく似ている挙動をするサービスを見つけることができました。その挙動がどのように実現されているのかをDevToolsのパフォーマンスタブやネットワークタブを用いて徹底的に調べ、解決方法を見つけることができました。

旧アーキテクチャ

f:id:hanahanayaman:20211224115000p:plain
旧アーキテクチャ図

新アーキテクチャ

f:id:hanahanayaman:20211224115020p:plain
新アーキテクチャ図

私たちのサービスは新たなアーキテクチャに乗り換えられ、(今この瞬間は)うまく動いています。

5-1-2. 戦略的に作った負債の回収

私たちのアプリケーションは一言でいうと「エンタメSNS」に当たります。機能として、投稿一覧で画像や動画などのリッチなコンテンツが見れたり、他にも様々なアニメーションや動的なコンテンツを提供しています。ユーザーを飽きさせないために、新しい機能を頻度高く提供をすることも多いです。

また、ブロックチェーンなどの不確実性の高い要素によってスケジュールの見積もりが難しい側面があり、時折、QCDでいうQualityを二の次にしDeliveryを優先した開発をすることもあります。そうして出来上がったコードは、当然ながら質が良いものではありません。

これは、前章までに挙げた「影響範囲が大きく、目に見える技術的負債」に当たります。ユーザーからは見えづらい負債であっても、後々すばやい機能開発やより良い体験の提供がしづらくなってしまうため、すぐに返済計画を立てる必要があります。実際に、弊社ではアジャイル開発をしているので、「次スプリントに負債返済を入れる」ことで解消しています。

また、このうちの一部は「影響範囲が小さく、目に見えない技術的負債」に当たります。その代表例になるのが、パフォーマンス劣化です。時間がない中で書いたコードは、吟味されたものではないため、その塵が積み重なると、いつのまにか目の前には大きな山ができあがっています。

この負債を返済をするためには、パフォーマンスチューニングという地道な作業をする必要があります。Gaudiyでは、この山を作らないようにするために「偶発的プログラミング」で挙げた「利用しているアルゴリズムとオーダー(O)を意識する」や「劣化が起きていないかCIのタイミングでLighthouseAPIを使いモニタリングを行う」を取り入れています。

5-2. 技術的負債を未然に防ぐ取り組み

最後に、そもそも借入をしないために、技術的負債を未然に防ぐ取り組みについてご紹介をします。

5-2-1. DDDの推進

DDDの目的は「影響範囲が小さく、目に見える技術的負債」を防ぐことです。

私たちのアプリケーションには複数のドメインが存在し、バックエンドではマイクロサービスの運用を行っています。ある時、追加開発を行う必要がでた時に、破壊的修正を要してしまうという問題を抱えていました。そこでDDDの導入を行いました。

結果的にドメインエキスパートの考え方やメンタルモデルをシステムに組み込むことができ、これによってレバレッジが効きつつも、柔軟性をもった開発ができるようになりました。これは「ビジネス的柔軟性」が原因で起こる負債を防ぐために機能しています。

5-2-2. ちょいコラ、ちょいデモ、マルチアイ

次に、パターン・ランゲージとして社内で使っている「ちょいコラ」「ちょいデモ」「マルチアイ」の取り組みです。この目的は「影響範囲が大きく、目に見えない技術的負債」を防ぐことにあります。

大前提として、人は誰しもがケアレスミスをしてしまいます。ですがこのミスは、他者とのコラボレーションをすれば防ぐことが可能です。それを日常的に意識するため、利用しているパターン・ランゲージが以下になります。

  • ちょいコラ…デザインとビジネスの観点をエンジニアリングに取り込みたいときに、担当者がその人達に助言をもらいにいく。
  • ちょいデモ…細かいサイクルでデモを実施して、実際に動くものを確認するタイミングを設けることで、ユーザー視点を最初から開発に取り入れる。
  • マルチアイ…偏った視点ではなく、複数の視点を交えて、最適解を導き出す。

これらは「偶発的プログラミング」や「コラボレーション不足」が原因で起こる負債を防ぐために機能しています。

5-2-3. オールオーナー(ALL OWNER)の考え

この行動指針は「影響範囲が大きく、目に見える技術的負債」を防ぐために機能しています。

どれだけ経験を積んできた人でも、勘違いや誤ったリードをしてしまうことがあります。この問題は、言われたことを鵜呑みにしないことで防ぐことが可能です。

Gaudiyには16のクレド(行動指針)がありますが、そのひとつに「オールオーナー(ALL OWNER)」という考えがあります。自律分散的なブロックチェーンの考え方に基づいて運営されている弊組織では「相談した上で、自身で最終決定をする」という考え方が存在します。

この考え方が組織で当たり前となっているため、プロダクトオーナーや、開発経験が長い人、年上の人、その他すべての人の意見を脳死で受け入れることはありません。これは「ビジネスプレッシャー」や「誤ったテックリード」が原因で起こる負債を防ぐことができます。

5-2-4. ドキュメントをすぐに作る文化

最後に、ドキュメント文化は「影響範囲が小さく、目に見えない技術的負債」を防ぐために機能します。

私たちは、様々な技術や言語、プラットフォーム、さらにブロックチェーンという変化の激しい先進技術を利用して開発に取り組んでいます。十数人のエンジニアしかいない組織ですので、いちコンテキストに関わっているエンジニアは、1〜3人程度です。つまり、設計背景や技術知識が簡単に属人化してしまいます。この「属人化」を防ぐために、実施したことや知見をNotionに蓄積しています。これもひとりだと後回しにしがちなので、朝会や夕会のタイミングでドキュメント作成をタスク化しています。

6. まとめ

この記事では、技術的負債をテーマに、発生原因や返済方法などを弊社の具体例を添えて書かせていただきました。

正直、私は恵まれていると思っています。というのも、未熟さが故に発生させてしまった技術的負債を解消する機会を設けてもらえているからです。

よく「コードの改修(=リファクタリング)をしてビジネス的になんの旨味があるの?」と問われたり、「リファクタリングをするならこの機能を作ってほしい」と要求をされる組織があるという話を聞きます。この時に、エンジニアは、WHYをしっかりと答える責任がありますが、(上下関係や心理的安全性の低さが故に)そのWHYを答えることすらできない組織もあると聞きます。

冒頭で質問させていただいた「所属している組織のコードを誇りに思い、この先数十年間に渡って使い続けることができると確信していますか?」という問いに 「YES!」 と答えることが出来ないのは仕方がないことかもしれません。でもこれは、エンジニアだけが悪いという話ではないと思っています。サービスを提供する組織全体として技術的負債を認知し、その返済をサポートする必要があると思っています。

この記事を読んだみなさんが少しでも技術的負債への解像度を高め、上記のような働きかけができるようになれば、書いた甲斐があるなと感じています。

ここまで読んでくださり、ありがとうございました。 書ききれていないこともあるので、よければカジュアルにお話しさせてください。

meety.net

techblog.gaudiy.com