GENZITSU / UsefulMaterials

34 stars 0 forks source link

almost weekly useful materials - 09/30 - #113

Open GENZITSU opened 1 year ago

GENZITSU commented 1 year ago

理想の声を目指して 〜七声ニーナの音声変換技術からライブ配信応用へ〜

DeNAが2022年3月まで公開していた音声変換サービス七声ニーナに用いられている技術の概要とリアルタイム音声変換の課題が紹介されている。

ボイスチェンジャーとの違い

ボイスチェンジャーは利用者が調整する必要があるが、低遅延

ボイスチェンジャーは、純粋な音声信号処理のため低遅延で安定性は高いというメリットはありますが、まったく同じパラメータでも利用者の地声によって変換音声の声色が変わってしまうというデメリットがあります。またいい声を作るには裏声を出すなど利用者側の熟練がある程度必要です。

音声変換は利用者がは特に意識する必要なく使えるが高遅延

音声変換は、機械学習を使って入力の声色から変換対象の声色への変換規則を音声データから自動学習させるアプローチです。誰の声でも完全に変換対象の声色に変えることも可能です。熟練も不要で誰でも使えるメリットがあります。一方で処理が重く、遅延が大きいというデメリットもあります。

音声変換の処理フロー

スクリーンショット 2022-09-15 21 53 21

特定のキャラクターの声だけに変換したい場合は Speaker Encoder を省略できます。

各モジュールで考えられるパターン

  • 学習に書き起こしテキストが必要かそうでないか?
  • 音声を波形領域で処理するか、スペクトル領域で処理するか?
  • 発話内容や話者性にどのような特徴量を使うか?

七声ニーナの音声変換アーキテクチャ

スクリーンショット 2022-09-15 21 58 10

誰の声でも七声ニーナの声色に変換するために入力音声から音素表現を抽出する音声認識ベースのアプローチを採用しました。入力音声を音素認識モデルで音素表現に落とし込むことで入力話者の話者性を完全に消すことができます。

音素認識モデルは大規模な音声コーパスで訓練しており、利用者ごとの音声収録は不要です。また音声生成モデルは音素表現から七声ニーナの音声を生成するように学習しており、七声ニーナの声色を完全に再現できます。

また CPU でもリアルタイム動作できるほど軽量で高速な音素認識モデルと音声生成モデルを組み合わせたアーキテクチャ

新たにイントネーションを予測するモジュールを追加するのではなく、音素認識とマルチタスクで同時に求めたり、イントネーションを正規化・量子化するなどの細かい工夫を実施

元サイトではイントネーションによる生成音声の違いを聞くことが可能

リアルタイム音声変換の作り方

スクリーンショット 2022-09-15 22 02 49

リアルタイム音声変換の実装では 2 つのバッファを使います。入力音声を保存しておく入力リングバッファと変換音声を格納しておく出力リングバッファです。リングバッファは終点と始点がつながった配列のようなデータ構造です。

マイクから入力した音声は入力リングバッファに蓄積されます。音声変換アルゴリズムは指定のブロックサイズだけ音声が蓄積されたら入力リングバッファから取り出して音声を変換します。変換音声は出力リングバッファに格納し、スピーカーから出力します。

ブロックベース音声変換は非常に高速に動く必要があります。変換処理が重すぎると入力リングバッファがあふれてしまいますし、出力リングバッファが空になって音が途切れてしまいます。

リアルタイム音声変換は50 ~ 70 ms程度の低遅延さが求められる

配信者の多くは変換音声をヘッドフォンで聴きながら配信しているそうです。自分の話し声を少し遅らせて(50〜200 ミリ秒)聴きながら話すと話しづらくなる現象が知られていますが、そのような現象が起きないほど遅延が短いことが期待されます。具体的には 50〜70 ミリ秒が期待されています。

しかし、実際にはブロックサイズを小さくしながら高性能な音声変換を実現するのはかなり難しい。

スクリーンショット 2022-09-15 22 06 32

七声ニーナのリアルタイム変換の実装ではブロックサイズを最低でも 300 ミリ秒以上は取らないと変換品質が大幅に悪化することがわかっており、これ以上の低遅延化は難しいと判断しました。

コメント

リアルタイム音声変換技術の難しさがなんとなくわかった。
ブロック長を短くしても高精度な変換ってのは何を仮定すればいいのだろうか...

出典

理想の声を目指して 〜七声ニーナの音声変換技術からライブ配信応用へ〜

GENZITSU commented 1 year ago

『FF7 リメイク』進化したリップシンク技術を実例付きで紹介。テキスト入力不要でアニメーション生成が可能! 機械学習により別次元のクオリティーへ【CEDEC2022】

キャラクターの発話と唇の動きを一貫性のある自然な形でアニメーション生成するリップシンク技術を機械学習により高精度化した事例の紹介。

発話と唇の動きに一貫性を持たせたいのは山々だが、手作業で修正していくには無理がある。。

スクリーンショット 2022-09-15 22 45 45

そのため、多くの企業が現在もリップシンクアニメーションの自動生成技術開発に取り組んでいる。スクウェア・エニックスでは従来、“音素”をベースにした“HappySadFace”(以下、HSF)というリップシンクアニメーション作成プログラムを使用していた。しかしこのシステムにも問題がいくつかあり、それを解消すべく新たに“Lip-Sync ML”という、“機械学習”をベースとしたシステムを開発したという。

スクリーンショット 2022-09-16 0 20 38

Happy Sad Face の概要

キャラクターの発話を音素に分解して、各音素を唇の動きが事前に定義された特定音素の重ね合わせで表現することで最終的な動きを求める。

スクリーンショット 2022-09-15 23 00 49

スクリーンショット 2022-09-15 23 00 55

スクリーンショット 2022-09-15 23 01 11

スクリーンショット 2022-09-16 0 22 20

なかなかいい手法なのだが、アドリブや呼吸音に対する対応が難しかったらしい。

『FF7 リメイク』のヒロイン・エアリスのリップシンクアニメーション動画を再生したが、明らかにセリフがない部分で、大きく口が動いていた。言葉を発する直前の呼吸音に音素として反応し、アニメーションが生成されてしまったのだ。

スクリーンショット 2022-09-19 22 56 52

スクリーンショット 2022-09-16 0 22 54

これを解決したのLip Sync ML

Lip Sync ML

上述の問題を解決し、より自然な唇モーションを生成することが可能な機械学習ツール。
下記のように訓練データにないキャラクターや人間ではないキャラクターにたいしても器官点さえ定義できれば適用可能。

スクリーンショット 2022-09-16 0 24 24

スクリーンショット 2022-09-16 0 24 34

どうやって作ったか?

スクリーンショット 2022-09-16 0 26 49

多数のデータが2秒程度の短いものばかりで、長いデータとの差異が生じかねないという問題もあったが、近似データを連結することでこの問題は解決した。

音声の速度や異なるキャラクターによるピッチの変化に対し、ロバスト性(外部の要因に影響されにくい性質)を向上させるためにいくつかのデータ拡張を実施。ランダムで速度やピッチを変化させたクリップを、訓練データに混ぜた

スクリーンショット 2022-09-19 22 50 12

スクリーンショット 2022-09-19 22 50 21

スクリーンショット 2022-09-19 22 51 29

スクリーンショット 2022-09-19 22 51 41

アーキテクチャーは以下

スクリーンショット 2022-09-16 0 28 32

データの流れ

スクリーンショット 2022-09-19 22 43 00

スクリーンショット 2022-09-19 22 42 48

音源をログメルスペクトログラムに変換

音声モデルは生のオーディオ信号をモノラルに変換し、19.2kHzにリサンプリングする。一般的なレートではないのは、アニメーションフレームと音声サンプルとの適切な同期を確実にするため

スクリーンショット 2022-09-19 22 46 16

コメント

音声にマッチしたアニメーション生成というタスクでルールベースによる処理をMLモデルに正当に進化させている良い事例。

一見事前学習いるのか?というようなタスク設定ではあったが、オープンドメインデータによる事前学習で性能が上がっているのは普段の業務で意識しておきたいポイントかもしれない。

出典

『FF7 リメイク』進化したリップシンク技術を実例付きで紹介。テキスト入力不要でアニメーション生成が可能! 機械学習により別次元のクオリティーへ【CEDEC2022】

GENZITSU commented 1 year ago

時系列データを前処理する際のPython逆引きメモ

時系列データを扱う際によく扱う処理が一覧になってまとまっている。

参考になったものだけ抜粋

スクリーンショット 2022-09-19 23 03 42

各行の時間差分を求める

一旦、秒で取得して60で割っている

# https://www.eureka-moments-blog.com/entry/2022/09/13/221213
data_df["dif_min"] = data_df["date"].diff().dt.total_seconds() / 60
data_df["dif_min"] = data_df["dif_min"].fillna(0)
print(data_df["dif_min"].head())

特定日時との差分を求める

対象日時も一旦datetime型にしているのがポイント

# from https://www.eureka-moments-blog.com/entry/2022/09/13/221213

event_df["date"] = pd.to_datetime(event_df["date"], format="%Y-%m-%d %H:%M:%S")
base_time = "2016-01-11 17:00:00"
event_df["dif_min"] = event_df["date"] - dt.datetime.strptime(base_time, "%Y-%m-%d %H:%M:%S")
event_df["dif_min"] = event_df["dif_min"].dt.total_seconds() / 60

コメント

メモ

出典

時系列データを前処理する際のPython逆引きメモ

GENZITSU commented 1 year ago

Make Better Bar Charts in Python using Pandas Plot

pandasのdf.bar()を用いていい感じなグラフを生成するためのtips集

参考になったものだけ抜粋

スクリーンショット 2022-09-19 23 16 24

積み上げ棒グラフ

# from https://www.shanelynn.ie/bar-plots-in-python-using-pandas-dataframes/

plotdata.plot(kind='bar', stacked=True)
plt.title("Total Pie Consumption")
plt.xlabel("Family Member")
plt.ylabel("Pies Consumed")

スクリーンショット 2022-09-19 23 16 46

積み上げ順の変更

# from https://www.shanelynn.ie/bar-plots-in-python-using-pandas-dataframes/

plotdata[["pies_2020", "pies_2018", "pies_2019"]].plot(kind="bar", stacked=True)
plt.title("Mince Pie Consumption Totals")
plt.xlabel("Family Member")
plt.ylabel("Pies Consumed")

スクリーンショット 2022-09-19 23 18 01

描画するものを選ぶ

# from https://www.shanelynn.ie/bar-plots-in-python-using-pandas-dataframes/

plotdata.reset_index().plot(
    x="index", y=["pies_2018", "pies_2019"], kind="bar"
)
plt.title("Mince Pie Consumption 18/19")
plt.xlabel("Family Member")
plt.ylabel("Pies Consumed")

スクリーンショット 2022-09-19 23 19 36

カテゴリーごとに色分けする

# from https://www.shanelynn.ie/bar-plots-in-python-using-pandas-dataframes/

colours = {"male": "#273c75", "female": "#44bd32"}
plotdata['pies'].plot(
    kind="bar", 
    color=plotdata['gender'].replace(colours)
)

スクリーンショット 2022-09-19 23 20 55

凡例のレイアウトを変える

n_colsで行数を変えることが可能

# from https://www.shanelynn.ie/bar-plots-in-python-using-pandas-dataframes/

# Plot and control the legend position, layout, and title with .legend(...)
plotdata[["pies_2020", "pies_2018", "pies_2019"]].plot(
    kind="bar", stacked=True
).legend(
    loc='upper center', ncol=3, title="Year of Eating"
)
plt.title("Mince Pie Consumption Totals")
plt.xlabel("Family Member")
plt.ylabel("Pies Consumed")

コメント

df.barで積み上げ棒グラフ作れるの知らなかった。

出典

Make Better Bar Charts in Python using Pandas Plot

GENZITSU commented 1 year ago

AI Project Management Flow and Build Trap Review

不確実性の高い機械学習プロジェクトを円滑に進め最大限の成果を得るためのマネジメント戦略について述べられたスライド。

DeNAで長年MLプロジェクトをマネジメントされているyurfuwaさんが書かれた力作。

yurfuwaさんが書いたAI Project Management Anti Patternも良作なので是非読まれたい。

正直全スライド必読ではあるのだが、キリがないので特に重要なポイントのみメモ

ML PRJの課題

  • 機械学習プロジェクトが増えていく中で、PoCの終了条件とMVPの境界前提が確立し なままプロジェクト進行するケースが存在する
  • PoCが不完全なままMVPを進行した場合、前提条件の破綻とコスト増大リスクを抱え ることになる
  • チームのレベル差にはバラツキがあり、PjM/PdMも例外ではない。ある種のスーパ ーマンの成功体験のみを生存バイアスとして活用することは依存であって、持続的か つスケーラブルな組織を目指さねばならない

多くのML PRJのPoCは終了条件が不明瞭 ないしは 何がなんでもPoCを終わらせることが宿命づけられている印象
実際はPoCをちゃんとやらないことで後の工程の工数を漠増させる結果になりがち。 また、ML PRJの属人性は他のシステム開発よりも高いので、意識的にサステナブルな組織を目指す必要がある。

アプローチ

  • アセスメント、PoC、MVPのフェーズ終了条件/境界を定め、フレームワーク(AI Project Management Flow)にすることで個々に目指すべきゴールが明確になり、イテレーション回数を増やし、結果的にプロダクト価値の最大化と案件ごとの品質差異を最小化する
  • 合わせて多面的なビルドトラップレビューを行い、組織長のような管理者ではなく、自律的なチーム同士がプロジェクトのゴール確認・健全性のチェック・品質の均一化・そしてそれらのナレッジトランスファーを行うことで、効率的にチームが提供する機械学習プロダクトのアウトカムを最大化しながら、組織のスケーラビリティを高める

ここの工程をアジャイルで進めるのは良いが、一工程ずつの達成条件/撤退条件を作成してフレームワーク化する
また、チームメンバー同士のレビューを通してナレッジシェアを行うことで、ML実装に係るリスクの最小化と組織の成長を目指す必要がある。

よくあるML PRJ のフロー

スクリーンショット 2022-09-20 23 21 21

とくに注意しなければいけない点は下記

  • 先方ビジネス課題のヒアリング
    • 渉外 or BizDev + データサイエンティスト or アナリスト
    • ✗UXデザイナーやエンジニアは随分後から適宜合流
  • △Proof of Concept で検証サイクルを回しながら本番運用化を探る
    • PoCと運用のシステムアーキテクチャは全く異なる可能性が考慮されていない
  • ✗ ステークホルダーとその担当者によって各レベルの理解がまちまち

アジャイルに潜むビルドトラップ

AI PRJ における PoCとはなにか

  • AIプロジェクトの概念では AI/DSモデル開発のフィージビリティとする
  • 基本的に仮説検討した、「アルゴリズムの実証」を行う
  • サービス向けのインターフェース開発及びプロトタイプ開発を伴わない

AI PRJにおけるMVPとはなにか

  • PoCで実装された開発モデルを「サービスに組み込み検証」する「最小プロトタイプ開発」
  • 当然成果物としてプロダクト開発を伴う
    • ただし、UIはあってもなくても良い
  • PoC自体もMVPを意識した上でモデル開発に注力すべきなので、PoCでモデル開発に時限を区切り、MVPでエンドユーザーを意識した最小のプロダクト開発を行うというのがポイント
  • 勿論PoCのアルゴリズムが実証されても、MVPの体験検証でアセスメント (課題設定)の引き直しからやり直す事もありえる。
  • 重要なことは、この単位をいかに最小構成に定義しイテーレーションを繰り返すことができるのか、にかかっている。

よくある罠: プロダクトとしての要件をおざなりにしてアルゴリズムのフィージビリティにリソースを投下しすぎる

  • いつのまにかPoCの流れでPdMを介せずにMVP要件をヒアリングを実施し場当たり的にリソースを調整

  • = いつのまにか非専門領域のインターフェース実装を任される

  • 時間的・予算的にPdMやUXデザイナー/SEWを入れていない

    • 一旦AIエンジニアがMVP開発まで良かれと思ってやってしまう
    • ✗ MVPとしてのPdMやUXの観点がまるっと抜けてしまう
  • ヒアリングとその場の判断でMVPに必要な要件をなんとなく確定している

    • ✗ その要件が本当に顧客にとって必要なものかフィージビリティがとれていない
    • ✗ アルゴリズム開発が先行し、UXやユースケースの深掘りをはじめ、MVP開発は後手に

どうするべきか?

PoCとMVPとプロダクト開発の境界をはっきりさせる

  • 機械学習のPoCはアルゴリズムの提案と解法レポートに集中する。
  • アルゴリズム検証PoCでMVPの要件をコミットをしてはならない
  • PoCフェーズを終了しMVPはMVPで体制から「仕切り直す」
  • PoCとMVP,本開発それぞれのゴールを細分化したコンセンサスが必要

これらを実施することでステークホルダー全員がPRJの先を見れるようになる。

以下のようなマネジメントフローが理想的とのこと

スクリーンショット 2022-09-20 23 40 55

  • レベル及びフェーズで各プロジェクトをnotionで管理
  • レベル単位のサイクルで以下を実施
    • 「体制見直し」,「全体キックオフ」, 「振り返りと評価」

これらを実施することで、得られるメリット

各レベルやフェーズで実施すべきこと

スピード先行によってできなかったチーム開発品質を維持する施策実施

  • リファクタリング,テスト,ドキュメンテーションなどの運用品質向上
  • 特に体制見直しに合わせた新メンバーのオンボーディングで効果を発揮
  • 新メンバーが旧メンバーとペアプロやSyncをしながら進めるのが◎
    • プロジェクトマネジメントツール、手法の見直し
    • 新メンバーが入ることを踏まえた前フェーズからのドキュメント整備
    • 全体KPTを必ず実施し、チーム開発課題を洗い出す
  • 前フェーズで課題を残したまま新メンバーを入れて新フェーズに入ることを許さない

特にこういったことは意識的にゆとりを作らないと後回しになりがちなので、自動的にフェーズ境界で時間とリソースのゆとりが発生する上記のマネジメントフローと相性がいいかもしれない。
ここで発生させたゆとりを別PRJに食いつぶされることもよくあるが笑

ビルドトラップレビュー

ビルドトラップとは

機能の開発とリリースに集中してしまい、顧客の本当の課題、プロダクトの本当の価値がおざなりになってしまう状況

これに陥らないためにどんなレビューを実施するべきか

  • そのフェーズにおける、ゴールを確認
    • PjM/PdMがプロジェクトやAIプロダクトに対する短期および中長期のゴールを答えられないようでは話にならない。 -そもそもプロジェクトの目的とアウトカムが定まっているか。
    • PoCからMVPを経てアウトカムがブレていないか。

このゴールの明確化と妥当性を確認するだけでも、時間をかける価値があるとのこと

くわえてやれるといいこと

  • Role/リソースの短期・中長期妥当性
    • ○ 現フェーズで非専門領域に対するフィージビリティを門外漢がやっていないか
    • ○ 現フェーズの見通しにより、次フェーズの準備で行うべきタスクが整理/実施されているか
  • 法務セキュリティ関連
  • AIガバナンス観点

その他の論点

  • アウトカムに立ち返ることが最も重要
  • 適切なタイミングで適切なプロを入れる仕組みとコンセンサスをする
  • 駄目だったら撤退できる余裕を作る
  • 焦らないで地道にやれる仕組みを作る
  • スピード感とは、「感」ではなく「不確実性を減らし先を見通す力」と、その実行力である

タイミングを適切に分ける、タイミングごとに振り返りや調整を行う、イテレーションを回す余裕を作るなど

どれも大事だけど実行が難しい...

コメント

後半に書いてあった心強い言葉が強く胸に響いた

  • 多角事業組織は、一つの成功体験がいくつもの別の事業での成功に横展開できることが最大の強みである。実績を積み上げ、その実績を別の課題・ユースケースに活かすことも、持続的な組織戦略となる
  • ○ 単なるプロジェクトの成功秘話にとどまらず、アルゴリズムの技術的課題から性能改善からププロダクトのアウトカムに繋げる具体施策までチームが持って変えるナレッジに底は無い

実行するのが難しいものばかりであるが、一つ一つ積み上げ無いと強くはなれない...

出典

GENZITSU commented 1 year ago

Python coding practices / Guildlines for inheritance

odashiさんが書かれたpythonで継承を実装する際のガイドライン

勉強になったところだけ抜粋

ABCを継承するのではなく、metaclassを利用する

# from https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

class Vehicle(metaclass=ABCMeta):
    @abstractmethod
    def run(self) -> None:
        ...

継承を用いると、以下のようにis-aの関係が生じてしまうため

# from https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

class Vehicle(ABC):
    ...

# Vehicle accidentally has the "is-a" relationship with ABC.
assert issubclass(Vehicle, ABC)

compositionパターンを適宜利用する

以下のようなimplementation patternによる実装は不必要なis-aの関係を生じさせてしまう

# from https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

class Engine:
    def start(self): ...
    def stop(self): ...

# Car is-implemented-in-terms-of Engine.
# The inheritance must be hidden in this case,
# but Python does not provide such functionality.
class Car(Engine):
    def drive(self):
        self.start()
        ...
        self.stop()

my_car = Car()
assert isinstance(my_car, Car)  # Returns True.
assert not isinstance(my_car, Engine)  # Also returns True!

以下のように別クラスで実装したものを内部に保有する、composition パターンで回避したほうがよい


class Engine:
    def start(self): ...
    def stop(self): ...

# Defining Car with composition.
# Implementation can be replaced by composition in most cases.
class Car:
    def __init__(self):
        self._engine = Engine()  # Car has-an Engine.

    def drive(self):
        self._engine.start()
        ...
        self._engine.stop()

my_car = Car()
assert isinstance(my_car, Car)  # Returns True.
assert not isinstance(my_car, Engine)  # Returns False.

むやみに便利関数をbase classに実装しない

以下のように重さの単位を変える便利関数をbase classに実装したくなる時があるが、この便利関数があらゆる継承先で本当に必要になるかを感がなければならない。

# https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

class Vehicle(metaclass=ABCMeta):
    @abstractmethod
    def weight(self) -> float:
        # This function returns the physical weight of this object in kg.
        ...

    def weight_in_lb(self) -> float:
        # This function returns the physical weight of this object in lb,
        # but converting the unit seems to be not a responsibility of this class.
        return 2.20462 * self.weight()

class Car(Vehicle):
    def weight(self) -> float:
        return 1000.0

>>> Car().weight_in_lb()
2204.62

時に必要で、時に不要なのであれば、便利関数を切り出した方が得策である。

# https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

"""vehicle.py"""

class Vehicle(metaclass=ABCMeta):
    @abstractmethod
    def weight(self) -> float:
        # This function returns the physical weight of this object in kg.
        ...

"""car.py"""

class Car(Vehicle):
    def weight(self) -> float:
        return 1000.0

"""weight_utils.py"""

# Utility function to convert the unit of weights.
def kg_to_lb(kg: float) -> float:
    return 2.20462 * kg

>>> kg_to_lb(Car().weight())
2204.62

Factory機能はbase classと独立させる

以下のようにbase classに継承先のインスタンス化機能を持たせてしまうと、メンテナンスも複雑になるし循環参照を生じさせてしまう。

# https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

"""vehicle.py"""

from mylib.car import Car  # Circular dependency!
from mylib.train import Train  # Circular dependency!
from mylib.airplane import Airplane  # Circular dependency!
...
# We need to change the behavior of Vehicle every time a new subclass is added.

class Vehicle:
    def create_vehicle(name: str) -> Vehicle:
        if name == "car":
            return Car()
        ...

"""car.py"""

from mylib.vehicle import Vehicle  # Circular dependency!

class Car(Vehicle):
    ...

以下のように独立させるべし。

# https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

"""vehicle_factory.py"""
# This module is a sink of the dependency chain.
# There is no dependency from modules below to this module.

from mylib.vehicle import Vehicle

from mylib.car import Car
from mylib.train import Train
from mylib.airplane import Airplane
...

def create_vehicle(name: str) -> Vehicle:
    if name == "car":
        return Car()
    ...

dataclassの継承を避ける

メンテが大変になるのは想像に難くない。

# https://predicatejp.notion.site/Guidelines-for-inheritances-e9837f55d3774bb4b2f22776ba2d7386

@dataclass
class BaseData:
    one: int
    two: float

@dataclass
class MyData(BaseData):
    three: str
    one: str  # Overridden!

コメント

実務で継承をあまり活用したことがなかったが、勉強になった。

出典

Python coding practices / Guildlines for inheritance

GENZITSU commented 1 year ago

外部パートナーとのAPI連携時に気をつけるポイント

他社や外部のパートナーに作ってもらったAPIと連携をする際の注意点が整理されているブログ記事。

なるほどと思ったところだけ抜粋

1. 仕様書が最新であり、内容に漏れ、ダブり、誤字脱字がないことを確認する

仕様書と実態の実装が違うことで、使い方が間違っているのか、現状が正しいのかわからず確認作業に時間を溶かすといったことが容易に起きえます。

定期的に仕様書が最新であるかのコミュニケーションを取るのが良さそう。

3. API連携の骨子を確認する

以下の要点を押さえておけばOK。

  • 通信方式
  • リクエストフォーマット / レスポンスフォーマット
  • リクエストヘッダー (Content-Typeやアクセストークン)
  • 操作制約 (時間制約, ネットワーク制約, リクエスト制約)
  • ステータスコード (HTTP固有, 独自定義)
  • エンドポイント / URLパス
  • 文字コード
  • 認証方式 / 認可方式

漏れなく抑えたい

4. フィールドの表現と値の意味を確認する

以下の要点を押さえておけばOK。

  • フィールドは必須なのか任意なのか
  • 必須でも空文字である場合、何らかの意味判定をするのか
  • フィールドがない場合の扱いをどう解釈するのか
  • 共通して要求されるフィールドがあるのか/ないのか
  • 数字の表現に特殊な法則はないのか
  • 文字数制限を設けている意図は何か、超えた場合どうなるのか
  • 配列である場合、件数制限はあるのか

仕様書だけだと発生する疑問は全て潰す。思いついた例外ケースも全て潰す。

6. リソースとフィールドのライフサイクルを明らかにする

リソースのライフサイクルというのは、リソース自体の作成、更新、削除といった状態遷移のこと。

フィールドのライフサイクルというのは、status といったフィールドで表現されるもので 、何らかの申請を行う場合には、申請前, 申請完了, 審査中, 承認, 非承認といった状態遷移が考えられます。

大凡の仕様書にはリソースに対する操作方法は明記されますが、自分達の操作以外で変わりうるケースが明記されていない場合があります。

ステータスの意味解釈は明記されていると思いますが、それがいつ, 何を起因に, どれに変わるのか, そこに制約はあるのか を把握するよう意識しましょう。

この手のAPIを作ったことはないが、確かに大事そう。

7. 参照APIは可能な限り用意してもらう

クライアント側で整合性を確認するには参照APIがなければできません。

当たり前だけ忘れそう

8. リソース操作 (作成 / 更新 / 削除) のAPIで冪等性を担保する仕組みを確認する

ネットワークエラーなどで、重複した操作を実施することが多々ある

例えば、特定のお客様に何らかの特典を付与するという場合に付与リクエストは通ったものの、レスポンス時にネットワークエラーが発生し、エラーだとみなして付与リクエストをリトライしたとします、この時エラーになったからといって安易にリトライしてしまうと、仮にAPIに冪等性がない場合、重複して特典を付与してしまうことになります。

9. 障害発生時のリカバリーとフォールバック方法を確認する

以下の問いに答えを出しておくと良いかもしれません。

  • 障害発生時にどの様に振る舞うのか
  • システムが復旧したらいつから正常処理を再開するのか
  • 何を基準に処理再開を判断して良いのか
  • 再開前に整合性を確認する必要があるのか
  • 双方のシステムで処理を経た結果、最終的なあるべき状態は何か

有事にアタフタしないように

有事に備えてパートナーとコミュニケーションパスを確立する

問題発生時に誰にどの手段で連絡を入れるのか、時間帯的にいつ頃に連絡するのがよく、社内外で誰が表に立ってやりとりするのかを双方認識を揃えておきます。

有事の際のコミュニケーションパスを確保するのも大事だけど、定期的なコミュニケーションの場を用意するのも良さそう。

コメント

ブログはパートナーにAPIを作ってもらう想定で書かれているが、作り手側も同様なことを意識する必要がありそう。
作る場合はこれん加えて負荷とかも気にしないとなのかな?

出典

外部パートナーとのAPI連携時に気をつけるポイント