1 ポイント 投稿者 GN⁺ 2 시간 전 | 1件のコメント | WhatsAppで共有
  • exeは、製品ロジックの各所で決済APIを直接呼び出す代わりに、状態変化を**請求可能な事実(billable facts)**として記録し、確定した状態をStripeと調整する
  • 従来の構造では、データベーストランザクションと決済API呼び出しが絡み合い、部分的な失敗、異常なサブスクリプション状態、決済拒否のような例外が製品フロー全体を揺るがしていた
  • チームの席数が追加されると状態をdirtyとしてマークし、後続のワーカーがビジネスルールに従って数量を計算し、変更があった場合にのみStripeのサブスクリプション数量を更新する
  • 決済を分離すれば、新規チームメンバーのオンボーディングは決済コードに依存せず、席数計算ルールを変えても招待や参加フローに影響しない
  • 同じ調整構造を、アクティブVMやディスク使用量のような従量課金やiOSのアプリ内課金にも適用し、製品イベントは維持したまま決済プロバイダーごとの連携だけを差し替えられる

製品フローから決済ロジックを分離する

  • 決済ロジックが一般的なビジネスロジックと混在すると、請求が必要なすべての重要経路に関連コードが広がり、価格体系も脆くなって変更しづらくなる
  • exeは、1人が決済知識を独占するのではなく、誰でも関連コードを変更できるようにしつつ、複雑な例外は専門担当者が処理する方式を志向している
  • 初期のチーム席数課金は、招待の受諾から決済までが1つの大きなフローとして束ねられていた
    • ユーザーが招待を受け入れ、アカウントを確認した後にチームへ参加する
    • 共有VMへのアクセス権と、料金プランに応じた計算資源が割り当てられる
    • この過程で決済APIも呼び出していた
  • このようにデータベース変更と外部API呼び出しを結合すると、片方だけが成功する部分的な失敗が発生しうる
    • チームのサブスクリプション状態が異常になることがある
    • 追加席数に対する決済が拒否されることがある
    • 例外が積み重なるほど、全体構造は脆弱になる

請求可能な事実と事後調整

  • 請求可能な事実は、特定の状態が変化したことを示す原子的な作業である
    • まず製品ロジックを実行し、リソースの新しい状態を確定する
    • その後、確定した事実をもとに決済プロバイダーの状態を調整する
    • Stripeに必要なのは、その状態に至る過程ではなく最終的な数量だけである
  • チーム席数の調整

    • 招待が受諾されると、チーム席数の状態をdirtyとしてマークする
    • 後続のワーカーがdirty状態を検知し、ビジネスルールに従って席数の増減を計算する
    • 数量が変わった場合にのみ、Stripeのサブスクリプション数量を更新する
    • チームメンバー追加と決済コードが分離されるため、招待フローを書き直しても課金が一緒に壊れず、席数計算方式も独立して変更できる
  • 従量課金とアプリ内課金

    • 同じ調整プロセスは、あらゆる従量課金に適用される
      • システムがアクティブVMとディスク使用量に関する事実を記録する
      • メータリングワーカーがそれを決済プロバイダーの状態と調整する
      • 新しい課金方式を追加しても事実そのものは維持され、各APIとどう調整するかだけが変わる
    • iOSアプリも、誰かがアプリ内課金でサブスクライブしたという事実だけを渡し、実際の決済状態はその後に調整する
    • 決済構造は、異なるメンバーでも扱える領域となり、招待フローのような製品機能変更が課金システムを損なう可能性も低くなる

1件のコメント

 
GN⁺ 2 시간 전
Lobste.rsの意見
  • 記事の核心である変更分を非同期に検知して処理する方式は、結合度を下げ、副作用を実装するのに適している。
    しかしLLMは、コードがあちこちに広がる現象を防ぐというより加速するツールなので、アーキテクチャ上の負債になりやすい。理解する速度より速く生成されるコードをどうレビューできるのかも疑問だが、Exeがコードレビューすらしていないというくだりはさらに怖い。

    • もともと真剣だったことがあまりないテック業界が、今はとりわけ不真面目な時期を通過していることを覚えておくべき
    • 請求システムを扱う立場から見ると、かなり怖いアプローチ。請求プラットフォームは複数の境界が明確なコンテキストで構成されるが、LLMはドメイン境界をうまく守れないため、大きな苦痛を招く可能性が高い
    • 「LLMを使っても」ではなく、特にLLMを使うとコードがさらに広がるのではないかと思った
    • その引用はOrwellではなく、Upton Sinclairの言葉だと認識している
  • このアーキテクチャは興味深いものの、記事の前半で提示した問題をどう解決するのかは不明。決済が拒否されると、すべてのリソースの支払いを保証するというより、未払いのリソースを先に提供することになりそう。
    請求ワーカーがdeclinedという事実を発行してリソースを回収することもできるが、きれいな一方向フローと比べると循環構造になる。Exeのように月次で請求するコンピューティングサービスには合うだろうが、物理機器を発送したり、他サービスのシートを再販売したりする事業では受け入れにくい妥協案。

    • 製品が抽象的で代替可能なソフトウェア中心の請求方式。従量課金は課金イベントが発生したという分析データをもとにし、請求システムがそれを集計して一貫した請求明細を作るほうがよい。課金イベントは複数の場所で発生し得るため、製品コードの外へ分離するのも健全。
      ただしAPI呼び出しやデータベーストランザクションの失敗、異常なサブスクリプション状態、シート決済の拒否をどう扱うかには直接答えていない。リファクタリングで分析収集が壊れたり、特定の行を変更状態として表示しなくなったり、新しい経路で変更表示を漏らしたりする問題もそのまま残る。
      シート数・無料枠の制限、最大支出額の設定、プリペイド残高の差し引きのように、製品内部に存在する請求関連の状態も解決できない。製品サービスがイベントを発行し、請求サービスがコンプライアンス状態を製品へ反映し直すことはできるが、そうすると状態を持つ分散システムに2つのアクターが生まれる
  • Stripeが数字を1つだけ欲しがっているように見えるが、一定規模では決済の明細項目まで提供すると、インターチェンジフィーを削減し、承認率を高められる

  • Exeがコードレビューをしない方式は新鮮。だとすると、リリースとテストはどのように運用しているのか気になる